1. 程式人生 > 其它 >CF1540C Converging Array 題解

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;
}