感觉是 good round。
2C
唯一没做明白的题。
经过若干手玩,发现在最优次数内达到目标,加的值是固定的。
也就是说,如果我加了 \(9\),想要达到目标,以后不可能再加 \(99\)。
又因为感觉答案上界很小,所以直接暴搜即可。
复杂度 \(O(能过)\)。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int inf=1e9;
const int a[10]={9,99,999,9999,99999,999999,9999999,99999999,999999999,9999999999};
int t,n,ans;
bool check(int n){while(n){if(n%10==7) return true;n/=10;}return false;
}
void dfs(int step,int n,int i){if(step>=ans) return;if(check(n)){ans=min(ans,step);return;}dfs(step+1,n+a[i],i);
}
signed main(){ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin>>t;while(t--){cin>>n;ans=inf;for(int i=0;i<=9;i++){dfs(0,n,i);}cout<<ans<<'\n';}return 0;
}
2D & 1A
趣味交互题。
首先,如果 \(x\) 不是一个排列,那么我们询问不在 \(x\) 中的数和任意数,返回 \(0\) 确定是 \(A\),否则确定是 \(B\);
然后,考虑 \(x\) 是排列的情况。此时如果是 \(A\),那么图一定是一棵内向基环树森林。
考虑图上两个点如果相互可达且距离相等,那么它们一定在同一个环上,并且距离的上界是 \(\lfloor \frac{n}{2} \rfloor\)。
所以我们选择 \(x_i=1\) 和 \(x_j=n\) 的两点询问,就可以确定是 \(A\) 还是 \(B\)。
#include<bits/stdc++.h>
using namespace std;
int t,n,a[200005],vis[200005],out;
void solve1(){int p,ans;if(out==n) p=n-1;else p=out+1;cout<<"? "<<out<<' '<<p<<endl;cin>>ans;if(ans==0) cout<<"! A"<<endl;else cout<<"! B "<<endl;
}
void solve2(){int minn,maxn,ans1,ans2;for(int i=1;i<=n;i++){if(a[i]==1) minn=i;if(a[i]==n) maxn=i;}cout<<"? "<<minn<<' '<<maxn<<endl;cin>>ans1;cout<<"? "<<maxn<<' '<<minn<<endl;cin>>ans2;if(ans1>=n-1 && ans1==ans2) cout<<"! B"<<endl;else cout<<"! A"<<endl;
}
int main(){cin>>t;while(t--){cin>>n;for(int i=1;i<=n;i++){cin>>a[i];vis[a[i]]=1;}for(int i=1;i<=n;i++){if(!vis[i]) out=i;}if(out) solve1();else solve2();for(int i=1;i<=n;i++){vis[i]=0;}out=0;}return 0;
}
2E & 1B
首先注意到,非 \(0\) 的数一定都能选。
然后注意到,\(0\) 至多只能选一个。
最后注意到,选择靠前的 \(0\),结果一定不劣于选择靠后的 \(0\)。
然后做完了。我们只需要判断选择第一个 \(0\) 和其他非 \(0\) 数,形成的子序列的合法性。
扫两边求前缀 \(min\) 和后缀 \(mex\) 即可。
总体复杂度 \(O(n)\)。
#include<bits/stdc++.h>
using namespace std;
const int inf=1e9;
int t,n,flag,a[200005],minn[200005],mexn[200005],cnt[200005],ans;
int main(){ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin>>t;while(t--){cin>>n;for(int i=1;i<=n;i++){cin>>a[i];if(a[i]) ans++;}if(ans==n){cout<<ans<<'\n';ans=0;continue;}flag=false;for(int i=1;i<=n;i++){if(!a[i] && !flag) flag=true;else if(!a[i]) a[i]=inf;}minn[0]=inf;for(int i=1;i<=n;i++){minn[i]=min(minn[i-1],a[i]);}for(int i=n;i>=1;i--){mexn[i]=mexn[i+1];if(a[i]<=n) cnt[a[i]]=1;while(cnt[mexn[i]]) mexn[i]++; }flag=false;for(int i=1;i<n;i++){if(minn[i]<mexn[i+1]) flag=true; }if(!flag) ans++;cout<<ans<<'\n';ans=0;for(int i=0;i<=n;i++){minn[i]=mexn[i]=cnt[i]=0;}}return 0;
}
2F & 1C
题面有点神秘。
实际上就是让你对每次操作后,都有 \((P,Q,R)\) 中两者相等。
不妨设 \(pre_i =\oplus_{j=1}^{i} a_j\)。
又因为第 \(i\) 次操作后,\(P \oplus Q \oplus R=pre_i\),所以 \((P,Q,R)\) 一定形如 \((pre_i,x,x)\) 或 \((x,pre_i,x)\) 或 \((x,x,pre_i)\)。
考虑 DP,设 \(f_{i,x}\) 表示前 \(i\) 次操作后,\((P,Q,R)\) 形如 \((pre_i,x,x)\) 或 \((x,pre_i,x)\) 或 \((x,x,pre_i)\) 的方案数。
考虑因为 \(x \oplus a_i \neq x\),所以当 \(x \neq pre_{i-1}\) 时 \(f_{i,x}=f_{i-1,x}\)。
所以只需要考虑 \(x=pre_{i-1}\) 的情况。
考虑怎样的三元组可以通过一次操作到 \(f_{i,pre_i}\),发现只有 \(f_{i-1,pre_{i-1}}\) 和 \(f_{i-1,pre_i}\),也就是说:
答案就是 \(\sum_{x} f_{n,x}\)。
然后把第一维压了,用 umap 维护合法状态,总体复杂度 \(O(n)\)。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
int t,n,a[200005],pre[200005],ans;
map<int,int> f;
signed main(){ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin>>t;while(t--){cin>>n;for(int i=1;i<=n;i++){cin>>a[i];pre[i]=pre[i-1]^a[i];}f[0]=1;for(int i=1;i<=n;i++){f[pre[i-1]]=(3*f[pre[i-1]]%mod+2*f[pre[i]]%mod)%mod;}for(map<int,int>::iterator it=f.begin();it!=f.end();it++){ans=(ans+it->second)%mod;}cout<<ans<<'\n';ans=0;f.clear();}return 0;
}