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