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


考虑把他转化为一个交换问题,可以交换的两个条件是 \(k\ge2\) 和 \(\exists i,j|b_i=b_j,j-i\le k (i<j)\)。
这是 \(k\neq 1\) 的情况,\(k=1\) 即转化为子序列问题。
CF1310E Strange Function

对于 \(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);
}
}

浙公网安备 33010602011771号