【CF1485F】Copy or Prefix Sum 题解

原题链接

题意简介

根据给定的数组 (B),现要求你构造出数组 (A),使数组 (A) 的每个位置 i,都满足下面的条件:

(A_i=B_i)(sum^i_{j=1}A_j=B_i)

求问数组 A 的构造方案有多少种?

思路分析

首先,从通过人数上看,这题比 E 题容易。

显然,这是一道计数的题目。

从题意我们可以看出,对于每个 i 位置上的数,只有下列两种可能:

  1. (A_i=B_i)

  2. (A_i=B_i-sum) (sum 为 (sum^{i-1}_{j=1}A_j)

假如每个位置都有上述两条世界线可以走的话,最终构造出的数组会有 (2^n) 种。

但事情并没有这么简单,我们发现,存在某些情况下,上述两个条件恰好等价,即 (sum=0)。此时,这一状态便没有两条世界线了。

于是,我们想到,维护到每个位置时各个 sum 对应的世界线的数量,然后在统计 i 的影响时,加入把上面的特殊情况取出来特殊考虑就行了。

不难看出,i 的影响如下:

  1. 将 sum 变为 (B_i)

  2. 将 sum 加上 (B_i)

对于第二种情况,可以用全局变量方便地维护。

利用 hash 表维护 sum 对应的世界线数量即可。

代码库

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,a,b) for(int i=a;i>=b;i--)
const ll N=2e5+5,mod=1e9+7,M=300007,STEP=233;
int T,n; ll B[N],delta; 
ll hsh[M],cnt[M];
inline int find(ll x){
    int p=(x-x/M*M+M)%M;
    while(cnt[p]!=0&&hsh[p]!=x) p=(p+STEP)%M;
    return p;
}
inline void add(ll x,ll c){
    int p=find(x);
    hsh[p]=x; cnt[p]=(cnt[p]+c)%mod;
}
inline ll count(ll x){
    int p=find(x);
    return cnt[p];
}
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        rep(i,1,n) scanf("%lld",B+i);
        memset(cnt,0,sizeof(cnt));
        memset(hsh,0,sizeof(hsh));
        delta=0; add(0,1); // sum 一开始只有 0 一种
        ll ans=1;
        rep(i,1,n){
            int tmp=(ans-count(-delta)+mod)%mod; // tmp 表示 i-1 的所有方案中 sum 不为 0 的情形 对应两种世界线都可以走的情况
            add(-delta,tmp); // 因为之后 bi 会加到 delta 上 所以此处对应 sum 直接变成 bi 的情况。
            ans=(ans+tmp)%mod; 
            delta+=B[i]; // 本来的情况直接加上 bi 的情形
        }
        printf("%lld
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Qing-LKY/p/CF1485F-solution.html