codeforces 1058E (思維)
阿新 • • 發佈:2018-11-05
題意:給n個數,每個數的二進位制1都可以隨意的換位置,問區間異或為0的有多少個
思路:該問題可以轉化為他的充要條件:
1.區間1的個數為偶數
2.區間最大值不超過區間和的一半;
偶數區間個數可以用cnt[i][2]記錄以1開始,1~i中偶數和奇數區間個數,
那麼偶數區間就是假如現在字首是偶數,那就加cnt偶數,反之加奇數。
因為偶數=偶-偶/奇減奇
對於不符合的,因為數是60位左右,所以最大值不超過60,假如有一個數是60那麼其他數至少為1,這樣往前 遍歷60來次
就足矣。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=3e5+10; int cnt[N][2], num[N]; int main(){ int n; //cout<<__builtin_popcount(1000000000000ll)<<endl; scanf("%d", &n); for(int i=1; i<=n; i++){ ll t; scanf("%I64d", &t); //num[i]=__builtin_popcount(t); while(t){ if(t&1) num[i]++; t>>=1; } //printf("%d ", num[i]); } //puts(""); cnt[0][0]=1; ll ans=0, sum=0; for(int i=1; i<=n; i++){ int s=0, mx=0; sum+=num[i]; if(sum&1) ans+=cnt[i-1][1]; else ans+=cnt[i-1][0]; cnt[i][1]=cnt[i-1][1]+(sum&1); cnt[i][0]=cnt[i-1][0]+(sum%2==0); for(int j=i; j>0&&i-j+1<=63; j--){ s+=num[j]; mx=max(mx, num[j]); if(s%2==0 && mx>s-mx) ans--; } } printf("%I64d\n", ans); return 0; }