【题解】CF1540C Converging Array
题意:
现在有长度为
的数组 和长度为 的数组 ,进行无穷次如下过程直至 数组值收敛。
- 选择一个数字
。 - 同时使
, (没有取整)。 定义
为操作完成后 的值。 现在你知道数组
和长度为 的数组 ,保证 。 有
组询问,每次问使 的数组 有多少个。
。
首先,对于上述操作,有几个比较基本的观察:
两个操作要么同时成功,要么同时失败。
第一个操作成功当且仅当
进行任意次操作,
保持不变。
因为
一次操作成功,当且仅当
,操作过后 。
因为上述操作实际上可以描述为先取平均数,然后左右各走
于是,假设
。 。
注意到,若对于任意
于是可以得到:
但是,我们知道并不一定所有
这是因为我们一次操作一定会使得
于是,总存在一个前缀
其中:
不过实际上,
首先,由于一定存在一个合法的
同时,假设对于一个前缀
这是因为,前缀
于是,结合上述两条观察,我们可以得出一个厉害的结论:
至此,我们得到了一种方式,能够快速通过
接下来考虑计数,
即:
这是一个背包的模型,设
但在困难版中,
感性地想,如果这个
需要满足什么条件?应该是:
即就算
因此,只有
因此,我们可以在
//Code By CXY07 - It's My Fiesta.
#include<bits/stdc++.h>
using namespace std;
//#define FILE
#define int long long
#define randint(l, r) (rand() % ((r) - (l) + 1) + (l))
#define abs(x) ((x) < 0 ? (-(x)) : (x))
#define popc(x) __builtin_popcount(x)
#define inv(x) qpow((x), mod - 2)
#define lowbit(x) ((x) & (-(x)))
#define ull unsigned long long
#define pii pair<int, int>
#define LL long long
#define mp make_pair
#define pb push_back
#define scd second
#define vec vector
#define fst first
#define endl '\n'
#define y1 _y1
const int MAXN = 110;
const int MAXX = 2e5 + 10;
const int SIZ = 1e4 + 10;
const int INF = 2e9;
const double eps = 1e-6;
const double PI = acos(-1);
const int mod = 1e9 + 7;
//const int mod = 998244353;
//const int G = 3;
//const int base = 131;
int n, m, q, prod = 1, c[MAXN], b[MAXN];
int L, R, sav[MAXX], sumb[MAXN];
int dp[SIZ], sum[SIZ];
bool vis[MAXX];
template<typename T> inline bool read(T &a) {
a = 0; char c = getchar(); int f = 1;
while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
while(c >= '0' && c <= '9') { a = a * 10 + (c ^ 48); c = getchar(); }
return a *= f, true;
}
template<typename A, typename ...B>
inline bool read(A &x, B &...y) { return read(x) && read(y...); }
int calc(int x) {
if(vis[x + (int)1e5]) return sav[x + (int)1e5];
vis[x + (int)1e5] = true;
memset(sum, 0, sizeof sum);
for(int i = 0; i <= n * m; ++i) sum[i] = 1;
for(int i = 1; i <= n; ++i) {
memset(dp, 0, sizeof dp);
for(int j = 0; j <= n * m; ++j) {
if(j < i * x + sumb[i]) continue;
dp[j] = sum[j];
if(j > c[i]) (dp[j] -= sum[j - c[i] - 1]) %= mod;
}
for(int j = 0; j <= n * m; ++j)
sum[j] = (dp[j] + (j > 0 ? sum[j - 1] : 0)) % mod;
}
return sav[x + (int)1e5] = (sum[n * m] + mod) % mod;
}
signed main () {
#ifdef FILE
freopen(".in", "r", stdin);
freopen(".out", "w", stdout);
#endif
read(n), m = 100;
for(int i = 1; i <= n; ++i) {
read(c[i]);
prod = prod * (c[i] + 1) % mod;
}
for(int i = 1; i < n; ++i) read(b[i]);
L = R = INF;
for(int i = 1, s = 0, si = 0; i <= n; ++i) {
sumb[i] = (i * s - si + mod) % mod;
(s += b[i]) %= mod, (si += b[i] * i) %= mod;
L = min(L, -sumb[i] / i - 1);
R = min(R, (i * m - sumb[i]) / i + 1);
}
read(q);
while(q--) {
int x; read(x);
if(x < L) printf("%lld\n", prod);
else if(x > R) puts("0");
else printf("%lld\n", calc(x));
}
return 0;
}