• [BZOJ4382][POI2015]Podział naszyjnika (神奇HASH)


    【问题描述】
        长度为n 的一串项链,每颗珠子是K 种颜色之一。第i 颗与第i-1,i+1 颗珠子相邻,第n 颗与第1 颗也相邻。
        切两刀,把项链断成两条链。要求每种颜色的珠子只能出现在其中一条链中。
        求方案数量。
    【输入】
        输入文件名为(neck.in)。
        第一行两个数n,K。
        第二行n 个数,第i 个数代表第i 颗珠子的颜色。
    【输出】
        输出文件名为(neck.out)。
        一行一个数表示答案。
    样例输入】   

        neck.in
        4 3
        1 2 3 3

     【样例输出

        neck.out
        3
     【数据范围与约定】
        对于20%的数据:n,K<= 10
        对于40%的数据:n,K<=1000
        对于100%的数据:n,K<= 1000000


    题解:

    称一个位置的后继为这个位置之后第一个与其颜色相同的位置。(i-1,i)表示i和i-1之间的间隔。

    如果一个位置有后继,那么将这个位置的权值加上一个较大的随机整数,后继的权值减去这个整数。(此处用HASH实现)

    设权值的前缀和为sum。

    设i,j为两个位置,那么如果sum[i]=sum[j],就认为(i-1,i),(j-1,j)可以成为一对切割位置。

    因为如果一个数和它的后继被分到不同两段,就会对一个sum产生贡献。

    复杂度O(nlogn)

    代码如下:

    #include<bits/stdc++.h>
    #define U unsigned
    #define N 1100000
    #define seed 19260817
    using namespace std;
    U long long pw[N],val[N],sum[N];
    long long ans;
    int n,K,tot,top,last[N],a[N],st[N],nex[N],vis[N];
    int main(){
        freopen("neck.in","r",stdin);
        freopen("neck.out","w",stdout);
        scanf("%d%d",&n,&K);
        pw[0]=1;
        for(int i=1;i<=n;i++) pw[i]=pw[i-1]*seed;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            if(last[a[i]]){
                val[last[a[i]]]+=pw[++tot];
                val[i]-=pw[tot];
            }
            last[a[i]]=i;
        }
        for(int i=1;i<=n;i++) sum[i]=sum[i-1]+val[i];
        sort(sum+1,sum+n+1);
        int now=0;
        for(int i=1;i<=n;i++){
            now++;
            if(i==n||sum[i]!=sum[i+1])
                ans+=(long long)now*(now-1)/2,now=0;
        }
        printf("%d",ans);
        return 0;
    }
    #include<bits/stdc++.h>
    #define U unsigned
    #define N 1100000
    #define seed 19260817
    using namespace std;
    U long long pw[N],val[N],sum[N];
    long long ans;
    int n,K,tot,top,last[N],a[N],st[N],nex[N],vis[N];
    int main(){
        freopen("neck.in","r",stdin);
        freopen("neck.out","w",stdout);
        scanf("%d%d",&n,&K);
        pw[0]=1;
        for(int i=1;i<=n;i++) pw[i]=pw[i-1]*seed;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            if(last[a[i]]){
                val[last[a[i]]]+=pw[++tot];
                val[i]-=pw[tot];
            }
            last[a[i]]=i;
        }
        for(int i=1;i<=n;i++) sum[i]=sum[i-1]+val[i];
        sort(sum+1,sum+n+1);
        int now=0;
        for(int i=1;i<=n;i++){
            now++;
            if(i==n||sum[i]!=sum[i+1])
                ans+=(long long)now*(now-1)/2,now=0;
        }
        printf("%d",ans);
        return 0;
    }
    自己选择的路,跪着也要走完
  • 相关阅读:
    20191117-STD::讲解及求平均数例题
    计算机网络-ip分类
    游标cursor
    ajax
    django ORM
    urls
    templates
    views
    models
    setting
  • 原文地址:https://www.cnblogs.com/tonyshen/p/11372869.html
Copyright © 2020-2023  润新知