BZOJ4750 密码安全

  按位统计,考虑每个数作为最大值的贡献,只需统计其左右有奇数个1和偶数个1的区间个数即可。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 100010
#define P 1000000061
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
int T,n,a[N],pre[N],suf[N],cntpre[N],cntsuf[N];
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj4750.in","r",stdin);
    freopen("bzoj4750.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    T=read();
    while (T--)
    {
        n=read();
        for (int i=1;i<=n;i++) a[i]=read();
        pre[0]=0;a[0]=a[n+1]=P;
        for (int i=1;i<=n;i++)
        {
            int j=i-1;
            while (a[j]<a[i]) j=pre[j];
            pre[i]=j;
        }
        suf[n+1]=n+1;
        for (int i=n;i>=1;i--)
        {
            int j=i+1;
            while (a[j]<=a[i]) j=suf[j];
            suf[i]=j;
        }
        int ans=0;
        for (int j=0;j<30;j++)
        {
            for (int i=0;i<=n+1;i++) cntpre[i]=cntsuf[i]=0;
            int s=0;
            for (int i=1;i<=n;i++)
            {
                s^=a[i]&(1<<j);
                cntpre[i]=cntpre[i-1]+(s>0);
            }
            s=0;
            for (int i=n;i>=1;i--)
            {
                s^=a[i]&(1<<j);
                cntsuf[i]=cntsuf[i+1]+(s>0);
            }
            int t=0;
            for (int i=1;i<=n;i++)
            {
                t^=a[i]&(1<<j),s^=a[i]&(1<<j);
                int x=t?cntsuf[pre[i]+1]-cntsuf[i+1]:i-pre[i]-(cntsuf[pre[i]+1]-cntsuf[i+1]);
                int y=s?cntpre[suf[i]-1]-cntpre[i-1]:suf[i]-i-(cntpre[suf[i]-1]-cntpre[i-1]);
                ans=(ans+1ll*a[i]*(1<<j)%P*(1ll*x*(suf[i]-i-y)%P+1ll*y*(i-pre[i]-x)%P))%P;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2018-11-15 22:43  Gloid  阅读(150)  评论(0编辑  收藏  举报