2024年11月18日 总结

四道结论题...

T1

简单数论题

赛时把线性筛板子

for(int i=2;i<=n;i++){
    if(!np[i]) p.push_back(i),...
    for(int j:p){
        if(1ll*i*j>n) break;
        ...
        if(i%j==0){
            ...
            break;
        }
        ...
    }
}

写成了

for(int i=2;i<=n;i++){
    if(!np[i]) p.push_back(i),...
    for(int j:p){
        if(1ll*i*j>n) continue;
        ...
        if(i%j==0){
            ...
            break;
        }
        ...
    }
}

喜提 40 pts。

早知道就测下大一点的数据了。

T2

不妨从大到小放权值,那么每次放的位置只能是先前放的位置的儿子。

考虑当前的可行的空位。那么无论放到哪里,如果当前点被钦定为叶子,总会使空位数量减一,否则,总会使空位数量加一。然后用乘法原理就可以了。

T3

题解没看懂

计数题一定要先会怎么判断

给定一个序列,如何判断它是 SCC 序列?

发现最优的加边策略一定是:

一定可以把点分为三部分:唯一一个大的 SCC,一个与该 SCC 相连的一堆单点串成的链(上面存在一些从前到后的边,构成一个 DAG),未连接的点。

保持 SCC 数量不变:先尽量把未连接的点连到链的末尾,否则在 SCC 中或链上连。

减少 SCC 数量:如果减少 \(k\) 个,就把链上的第 \(k\) 个点连到 SCC 即可,然后这 \(k\) 个点就合并进了 SCC 中。

考虑当前 SCC 的大小为 \(S\),链的长度为 \(L\),那么最多能容纳 \(S(S-1)+L(L-1)/2+SL\) 条边。

这样我们就可以写出暴力了

#include<bits/stdc++.h>
const int N=1e5;
int n,P,ans[N];
void dfs(int e,int S,int L){
	++ans[e];
	if(S+L<n) dfs(e+1,S,L+1);
	else if(e<S*(S-1)+L*(L-1)/2+S*L) dfs(e+1,S,L);
	for(int k=1;k<=L&&n-(S-1)-k>=1;k++)
		dfs(e+1,S+k,L-k);
}
int main(){
	int T;scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&P);
		memset(ans,0,sizeof(int)*(n+5));
		dfs(0,1,0);
		for(int i=1;i<=n*(n-1);i++) printf("%d ",ans[i]);puts("");
	}
}

考虑 DP。

\(f_{e,S,L}\) 表示上面的 dfs(e,S,L) 的访问次数。那么可以写出

#include<bits/stdc++.h>
const int N=110;
int n,P,ans[N];
int f[N][N][N];
int main(){
	int T;scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&P);
		memset(f,0,sizeof f);
		memset(ans,0,sizeof ans);
		f[0][1][0]=1;
		for(int e=1;e<=n*(n-1);e++){
			for(int S=1;S<=n;S++){
				for(int L=0;S+L<=n;L++){
					if(e<=S*(S-1)+L*(L-1)/2+S*L){
						if(S+L==n) (f[e][S][L]+=f[e-1][S][L])%=P;
						if(L) (f[e][S][L]+=f[e-1][S][L-1])%=P;
						for(int k=1;k<S;k++) (f[e][S][L]+=f[e-1][S-k][L+k])%=P;
					}
				}
			}
		}
		for(int i=1;i<=n*(n-1);i++){
			for(int S=1;S<=n;S++)
				for(int L=0;L<=n;L++)
					(ans[i]+=f[i][S][L])%=P;
			printf("%d ",ans[i]);
		}
		puts("");
	}
}

然后用前缀和优化就做完了。

T4

如果赛时有时间打表的话应该能做得出来吧(?

\(k\)\(\bigoplus_{i=1}^n a_i\) 的最大的非零位,则只消关心 \(a_i\) 的第 \(k\) 位,转化为 \(a_i=0/1\) 的情况,此时一定有奇数个 \(1\)

打表发现如果 \(n\) 是偶数则 Alice 必胜。证明考虑奇偶分组,那么 Alice 可以永远控制 Bob 取的位置的奇偶性。

如果 \(n\) 是奇数,需要尽量向 \(n\) 是偶数的情况化归。

如果两端都是 \(0\),那么无论 Alice 怎么取都会让 Bob 必胜,因此 Alice 必败。

否则,Alice 一定会选择一个 \(1\),Bob 面临的局势是 \(n\) 为偶数且有偶数个 \(1\)

如果 Bob 随后选了一个 \(0\),而 Alice 随后选了一个 \(1\),那么 Bob 的局势为 \(n\) 为偶数且有奇数个 \(1\),是必胜的。

因此可以推知 Alice 只能跟 Bob 选一样的。

然后打个表或者看大样例发现 Alice 和 Bob 一开始会消去头尾直到头尾不同,然后两个两个地消去。

posted @ 2024-11-18 21:47  justalearner  阅读(21)  评论(0)    收藏  举报