十月

很久没有记录了,写过的题都忘了,彻底废了。

arc183_b

image
image

考虑把他转化为一个交换问题,可以交换的两个条件是 \(k\ge2\)\(\exists i,j|b_i=b_j,j-i\le k (i<j)\)

这是 \(k\neq 1\) 的情况,\(k=1\) 即转化为子序列问题。

CF1310E Strange Function

image

对于 \(n\) 一定,\(k\) 越大,则 \(ans\) 越小,手玩发现 \(k\) 对答案规模的影响很大,考虑分类。

k=1

\(B = f(A)\),那么 \(\sum _{x \in A} =|B|\),有多少个集合 \(A\) 元素和小于 \(n\),dp 即可。

k=2

\(B = f(A) , C = f(B)\)

\(C=\{c_1,c_2\dots c_n\}\),其中 \(c_1 \ge c_2 \ge c_3 \dots\),容易发现,规模最小的 \(B\)\(c_1\)\(1\)\(c_2\)\(2\),依次类推,这样 \(A\) 的规模是最小的可以证明。

\[|A|=\sum c_i i \]

上面的 \(c\) 不增,直接 dp 会超时。差分一下,令 \(d=c_i-c_{i-1}\)\(d\) 增加等于增加 \(c_1\)\(c_i\),贡献为:。

\[|A|=\sum d_i\times i(i+1)/2 \]

不需要考虑大小关系,这个时候复杂度优化到 \(O(n^{1.5})\)

k>2

这个时候答案已经很小了,算出 \(n\) 对应的最大 \(c_1\),当 \(n=2020\)时,和最大为 \(64\)
爆搜,注意剪枝。

点击查看代码
bool check(int len){
	int now=0,to=1;
	int s=len;
	for(int i=1;i<=len;i++)
		b[now][i]=a[i];
	for(int i=1;i<k;i++){
		int cnt=0,c=0;
		ll sum=0,s2=0;
		for(int j=len;j>=1;j--)
			sum+=b[now][j]*(len-j+1);
		if(i+3<k && sum>23) return 0;//1
		if(sum>n) return 0;//2
		for(int j=len;j>=1;j--){
			++c; 
			for(int k=1;k<=b[now][j];k++){
				b[to][++cnt]=c;
				if(cnt>n) return 0;
			}
		}
		len=cnt;
		swap(now,to);
	}
	return 1;
}
void dfs(int len,int x,int s){
	if(s<=m && s!=0){
		if(check(len)) ans++;
		else return ;//3
	}
	for(int i=x;i<=m-s;i++){
		a[len+1]=i;
		dfs(len+1,i,s+i);
	}
}
posted @ 2024-10-15 10:13  point_fish  阅读(17)  评论(0)    收藏  举报