CF1540C Converging Array 题解

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;
}
posted @ 2021-08-23 10:15  Peal_Frog  阅读(65)  评论(0编辑  收藏  举报