kuangbinOJ B Lucky Sequence (hash大发)

题意:

给出一个序列,问子序列是k的倍数的个数。

题解:

用hash存0-n的前缀和,然后根据这个式子 (sum[j]-sum[i])%k=0 变形 (sum[j]%k+k)%k=(sum[i]%k+k)%k ,这样做为了保证负数也通过。然后只要查找是否目前hash中能找到多少个(sum[j]%k+k)%k。

#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define B(x) (1<<(x))
typedef long long ll;
void cmax(int& a,int b){if(b>a)a=b;}
void cmin(int& a,int b){if(b<a)a=b;}
void lcmax(ll& a,ll b){if(b>a)a=b;}
void lcmin(ll& a,ll b){if(b<a)a=b;}
const int oo=0x3f3f3f3f;
const int MOD=1000007;
const int maxn=1000007;
struct HASH_MAP{
    ll state[maxn],num[maxn];
    int next[maxn],head[maxn],tol;

    void Init(){
        memset(head,-1,sizeof head);
        tol=0;
    }

    ll check(ll s){
        ll ans=0;
        int h=(s%maxn+maxn)%maxn;
        for(int i=head[h];i!=-1;i=next[i]){
            if(s==state[i]){
                num[i]++;
                ans+=num[i];
            }
        }
        return ans;
    }

    void ins(ll s){
        int h=(s%maxn+maxn)%maxn;
        for(int i=head[h];i!=-1;i=next[i]){
            if(s==state[i])return;
        }
        state[tol]=s;
        num[tol]=0;
        next[tol]=head[h];
        head[h]=tol++;
    }
}mat;

int main(){
    //freopen("E:\\read.txt","r",stdin);
    int T,n,k,a;
    scanf("%d",&T);
    while(T--){
        mat.Init();
        scanf("%d %d",&n,&k);
        ll sum=0;
        ll ans=0;
        mat.ins(0);
        for(int i=1;i<=n;i++){
            scanf("%d",&a);
            sum+=a;
            ans+=mat.check((sum%k+k)%k);
            mat.ins((sum%k+k)%k);
        }
        printf("%lld\n",ans);
    }
    return 0;
}






你可能感兴趣的:(kuangbinOJ B Lucky Sequence (hash大发))