CodeForces-1030E 二进制位 dp

#include<stdio.h>
#include <unordered_map>
#include <algorithm>
#include <list>
#include <string.h>
#include <stdlib.h>
using namespace std;
#define LL long long
const int maxn=3e5+10;
LL a[maxn];
LL odd[maxn];
LL even[maxn];
LL sum[maxn];
int main() {
    #ifdef shuaishuai
    freopen("in.txt","r",stdin);
    #endif // shuaishuai
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",a+i);
        a[i]=__builtin_popcountll(a[i]);
        sum[i]=a[i]+sum[i-1];
    }
    LL ans=0;
    even[0]=1;
    for(int i=1;i<=n;i++)
    {
        LL mx=a[i];
        for(int j=i-1;j>=max(i-61,1);j--)
        {
            mx=max(mx,a[j]);
            LL s=sum[i]-sum[j-1];
            if(s>=mx*2&&s&1^1) ans++;//如果区间成立则 mx需要<=sum/2且sum是偶数,反证法可证
        }
        if(i>62)
            ans+=sum[i]&1? odd[i-63]:even[i-63];  //1e18以内的数最多62个1 所以对于极端情况 a1=a2=...a62=1 a63=62 只需将j遍历到2,j=1时aj有1的贡献,但是可推广开来计算.
                              //推广一下,对于 [i-61,i] 此时以a[i]结尾的合法序列除了ans统计的之外,还有根据sum[i]的奇偶不同而不同起点的序列,even[0]=1保证不漏掉a[1]...a[i]的序列的贡献 odd[i]
+=odd[i-1]+(sum[i]&1); even[i]+=even[i-1]+(sum[i]&1^1); } for(int i=1;i<=n;i++) printf("%lld ",sum[i]);printf("\n"); for(int i=1;i<=n;i++) printf("%lld ",odd[i]);puts(""); for(int i=1;i<=n;i++) printf("%lld ",even[i]);puts(""); printf("%lld\n",ans); return 0; }

猜你喜欢

转载自www.cnblogs.com/polya/p/9711021.html
今日推荐