星云俱乐部招新赛做题笔记
星云俱乐部招新赛做题笔记
语文(chinese)
简单题,考虑直接对有 \(m\) 条边的图跑 \(\text{Kruskal}\),求出最小生成树之后,容易发现,每删掉一条边,就会将图多分成两个部分。
所以只需将这颗最小生成树删去最长的 \(k-1\) 条边,就是最终答案。
赛时人均 AC 了。
int cnt=0;
for(int i=1;i<=m;i++){ //kruskal
int u=e[i].x,v=e[i].y,w=e[i].w;
int fu=Find(u),fv=Find(v);
if(fu==fv)continue;
fa[fu]=fv;
sum+=w,ans[++cnt]=w;
}
sort(ans+1,ans+1+cnt);
for(int i=cnt;i>=cnt-k+2;i--){ //删边
sum-=ans[i];
}
cout<<sum<<"\n";
政治(politics)
对于 \(k=1\),只存在一种方案,直接判断其是否可行 。
然后对于 \(k\geq 2\) 进行分类讨论:
- \(o=1\),即只需要满足一半限制。
由于只有两种限制:在同一天复习或不在同一天复习,那么仅需全部满足个数较多的限制即可。
如果要求同一天复习的天数较多,那么仅需全部放在同一天复习;
如果不能在同一天复习的天数较多,那么可以使用 \(01\) 染色,保证相邻颜色不同。
- \(o=2\),需要满足 \(3/4\) 的限制,考虑 \(3/4\) 这个数字的特点,容易发现只要先满足所有行的限制,再满足一半列的限制就行。
注意,如果在满足所有行的限制后,列无法满足一半的限制,那么只需要将所有行间染色全部反转,那么容易证明,一定可以满足限制。
所以 \(k\geq 2\) 的情况,一定有解。
特判 \(k=1\) 的情况:
赛时没有想出构造方案
int cnt=0;
for(int i=1;i<=n;i++)
for(int j=1;j<m;j++){
cin>>row[i][j];
cnt+=row[i][j];
}
for(int i=1;i<n;i++)
for(int j=1;j<=m;j++){
cin>>col[i][j];
cnt+=col[i][j];
}
int tot=2*n*m-m-n;
if(check(tot,cnt)){
cout<<"win!\n";
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
cout<<"1 ";
cout<<"\n";
}
return;
}
else{
cout<<"lost!\n";
return;
}
\(k \geq 2\) 的情况:
if(n>m){ //当 n>m 时,需要将这个矩阵翻转
flag_swap=1;
for(int i=1;i<=n;i++)
for(int j=1;j<m;j++){
cin>>col[j][i];
}
for(int i=1;i<n;i++)
for(int j=1;j<=m;j++){
cin>>row[j][i];
}
swap(n,m);
}
else{
for(int i=1;i<=n;i++)
for(int j=1;j<m;j++){
cin>>row[i][j];
}
for(int i=1;i<n;i++)
for(int j=1;j<=m;j++){
cin>>col[i][j];
}
}
for(int i=n;i>=1;i--){
ans[i][m]=1;
for(int j=m-1;j>=1;j--){
ans[i][j]=row[i][j]? 3-ans[i][j+1] : ans[i][j+1];
} //满足行的限制
//判断一半列的限制
int cur=0;
for(int j=1;j<=m;j++){
cur+=((ans[i][j]!=ans[i+1][j])^col[i][j]);
}
if(cur>m/2){
for(int j=1;j<=m;j++)
ans[i][j]=3-ans[i][j];
}
}
/*输出*/
学校
设 \(f_{i,j}\) 表示 \(p_k=i\) 且 \(a_{p_k-1} \oplus a_{p_k}=j\) 的方案数。
令 \(all_i\) 表示以 \(i\) 结尾的不合法序列的数量,转移中再减去 \(all_{p_{k-1}}\)
转移方程:\(f_{i,j}=2^{p_{k-1}-1}-\sum_{k=1}^{p_{k-1}-1}f_{k,j\oplus s}-all_{p_{k-1}}\)
ll slove(){
pw_2[0]=1;
for(int i=1;i<=n;i++)
pw_2[i]=(pw_2[i-1]*2)%mod;
for(int i=1;i<=n;i++)
pos[a[i]]=i;
ll ans=0;
for(int i=1;i<=n;i++){
for(int j=0;j<(1<<m);j++){
ll cur=pos[j^a[i]];
if(!cur||cur>=i){
f[i][j]=0;
}
else{
f[i][j]=(pw_2[cur-1]-g[cur-1][s^j]-all[cur]+mod)%mod;
all[i]=(all[i]+g[cur-1][s^j]+all[cur]+mod)%mod;
}
}
for(int j=0;j<(1<<m);j++)
g[i][j]=(g[i-1][j]+f[i][j]+mod)%mod;
ans=(ans+1+mod)%mod;
for(int j=0;j<(1<<m);j++){
ans=(ans+f[i][j]+mod)%mod;
}
}
return ans%mod;
}

浙公网安备 33010602011771号