CF1540C Converging Array 题解
Link.
Codeforces C1
Codeforces C2
Luogu C1
Luogu C2
Problem.
定义每次序列 \(b\) 作用于序列 \(a\) 的操作为,选择一个 \(i\)
- \(a_i\leftarrow\min\left(a_i,\frac{a_i+a_{i+1}-b_i}2\right)\)
- \(a_{i+1}\leftarrow\max\left(a_{i+1},\frac{a_i+a_{i+1}+b_i}2\right)\)
定义 \(F(a,b)\) 表示经过无限次 \(b\) 作用于 \(a\) 的操作后,\(a_1\) 的大小。
问有多少个 \(\{a_i\}\),满足:
- \(\forall i\in[1,n],a_i\in[1,c_i]\)
- \(F(a,b)\ge x\)
Solution.
观察性质。
发现每次变化的 \(\min\) 和 \(\max\) 取的东西是一样的。
每次变化条件是 \(a_{i+1}-a_i< b_i\)
变化后 \(a'_i+a'_{i+1}=a_i+a_{i+1}\)
最后一定会有 \(\forall i\in[1,n),a_{i+1}-a_i\ge b_i\)
我们考虑怎么求出 \(a_1\) 呢。
必定存在一个唯一的 \(p\),满足
- \(\forall i\in[1,p),a'_{i+1}-a'_i=b_i\)
- \(a'_{p+1}-a'_p\ne b_p\)
然后我们发现如果刚开始 \(a_{x+1}-a_x>b_x\) 了,\(a_x\) 和 \(a_{x+1}\) 就不会变。
所以我们有 \(\sum_{i=1}^pa_i=\sum_{i=1}^pa'_i\)
这样就可以求出 \(a_1\) 了,为 \(\frac{\sum_{i=1}^pa_i-\sum_{i=1}^{p-1}(p-i)\cdot b_i}{p}\)
我们发现,如果枚举错了,\(p'\) 并不是满足上面条件的话。
我们可以发现有两种情况
- \(p'< p\),这样的话我们发现 \(\sum_{i=1}^{p'}a'_i<\sum_{i=1}^pa'_i\)
有解出来的 \(a_{wrong,1}>a_1\) - \(p'>p\),这样的话我们发现存在一个 \(a_{x+1}-a_x>b_x\)
同时也有解出来的 \(a_{wrong,1}>a_1\)
所以我们在不知道 \(p\) 的情况下求出所有的 \(a_{i,1}\) 最小值即可。
最小值都要 \(\ge x\),则有 \(\forall p\in[1,n],\frac{\sum_{i=1}^pa_i-\sum_{i=1}^{p-1}(p-i)\cdot b_i}{p}\ge x\)
\(sa_i\ge x\cdot i+\sum_{j=1}^{i-1}(i-j)\cdot b_j\)
发现左边值域是 \(100^2\),可以直接背包
发现不同的 \(x\) 只有 \(100\) 种。
思考它们有没有什么相同的性质,发现没有。
桥豆麻袋!\(O(100^4)\) 可过,然后就做完了。
Coding.
点击查看 C1 代码
//是啊……你就是那只鬼了……所以被你碰到以后,就轮到我变成鬼了……{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
char ch=getchar(),bz=0;x=0;
for(;ch<48||ch>57;ch=getchar()) if(!(ch^45)) bz=1;
for(;ch>=48&&ch<=57;ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
bz?x=-x:0;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}/*}}}*/
const int P=1e9+7;int n,q,c[105],b[105],X,lm[105],dp[105][10005],s[105][10005];
int main()
{
read(n);for(int i=1;i<=n;i++) read(c[i]);
for(int i=1;i<n;i++) read(b[i]);
read(q),read(X);if(X>100) return puts("0"),0;
for(int i=1;i<=n;i++) for(int j=1;j<i;j++) lm[i]+=(i-j)*b[j];
for(int i=1;i<=n;i++) lm[i]+=i*X,lm[i]=max(lm[i],0);
int m=0;for(int i=1;i<=n;i++) m+=c[i];
dp[0][0]=0;for(int i=0;i<=m;i++) s[0][i]=1;
for(int i=1;i<=n;i++)
{
for(int j=lm[i];j<=m;j++)
{
int qw=(j-c[i]-1<0?0:s[i-1][j-c[i]-1]);
dp[i][j]=(s[i-1][j]-qw+P)%P;
}
for(int j=lm[i];j<=m;j++) s[i][j]=(s[i][j-1]+dp[i][j])%P;
}
return printf("%d\n",s[n][m]),0;
}
点击查看 C2 代码
//是啊……你就是那只鬼了……所以被你碰到以后,就轮到我变成鬼了……{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
char ch=getchar(),bz=0;x=0;
for(;ch<48||ch>57;ch=getchar()) if(!(ch^45)) bz=1;
for(;ch>=48&&ch<=57;ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
bz?x=-x:0;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}/*}}}*/
const int P=1e9+7;int n,q,m,c[105],b[105],X,lm[105];
int LM[105],dp[105][10005],s[105][10005],rs[505],sc[105];
inline int solve(int X)
{
for(int i=1;i<=n;i++) {lm[i]=max(LM[i]+i*X,0);if(lm[i]>m) return 0;}
dp[0][0]=1;for(int i=0;i<=m;i++) s[0][i]=1;
for(int i=1;i<=n;i++)
{
for(int j=lm[i];j<=m;j++)
{
int ps=j-c[i]-1,qw=(ps<lm[i-1]||ps>m?0:s[i-1][ps]);
dp[i][j]=((j<lm[i-1]||j>m?0:s[i-1][j])-qw+P)%P;
}s[i][lm[i]]=dp[i][lm[i]];
for(int j=lm[i]+1;j<=m;j++) s[i][j]=(s[i][j-1]+dp[i][j])%P;
}
return s[n][m];
}
int main()
{
read(n);for(int i=1;i<=n;i++) read(c[i]);
for(int i=1;i<n;i++) read(b[i]);
for(int i=1;i<=n;i++) for(int j=1;j<i;j++) LM[i]+=(i-j)*b[j];
for(int i=1;i<=n;i++) m+=c[i],sc[i]=sc[i-1]+c[i];
int neg=1;for(int i=1;i<=n;i++) neg=1ll*neg*(c[i]+1)%P;
int L=1e9,R=1e9;for(int i=1;i<=n;i++) L=min(L,-LM[i]/i)-1,R=min(R,(100*n-LM[i])/i)+1;
for(int i=L;i<=R;i++) rs[i-L]=solve(i);
read(q);for(int x;q--;) read(x),printf("%d\n",x<L?neg:(x>R?0:rs[x-L]));
return 0;
}