CF876 F 思维 枚举
生活随笔
收集整理的這篇文章主要介紹了
CF876 F 思维 枚举
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
給你n個數,問有幾個區間滿足,區間內或操作大于區間內的任意數。
首先可以知道,兩數或操作的結果必定不會小于兩者間的最大值,也就是說對于一個區間中,不合法的狀態只有兩值或相等。那么我們可以考慮枚舉每個數,向左向右找到第一個或不相等的,那么該數對所有不合法區間的貢獻就能找到了,所以與其找合法的區間不如容斥找不合法的區間。
具體從左往右枚舉每個數,同時記錄該數某二進制位為0時,左側數中該位出現1的離i的最近位置,得到左邊界。右邊界類似。
然后就是要注意重復的數,重復的數出現直接就使區間不合法,左右兩側收縮邊界時只要有一側考慮重復數即可。
?
/** @Date : 2017-10-16 23:43:44* @FileName: F.cpp* @Platform: Windows* @Author : Lweleth (SoungEarlf@gmail.com)* @Link : https://github.com/* @Version : $Id$*/ #include <bits/stdc++.h> #define LL long long #define PII pair<int ,int> #define MP(x, y) make_pair((x),(y)) #define fi first #define se second #define PB(x) push_back((x)) #define MMG(x) memset((x), -1,sizeof(x)) #define MMF(x) memset((x),0,sizeof(x)) #define MMI(x) memset((x), INF, sizeof(x)) using namespace std;const int INF = 0x3f3f3f3f; const int N = 2e5+20; const double eps = 1e-8;int a[N]; LL l[N]; LL r[N]; LL t[N]; map<int, int>q; int main() {LL n;cin >> n;for(int i = 1; i <= n; i++)scanf("%d", a + i);LL ans = 0;for(int i = 1; i <= n; i++){l[i] = q[a[i]];//標記重復數位置,重復數必定使區間不合法for(int j = 0; j < 31; j++){if((a[i] & (1LL << j)))t[j] = i;else l[i] = max(l[i], t[j]);}q[a[i]] = i;}for(int i = 0; i < 31; i++)t[i] = n + 1;for(int i = n; i >= 0; i--){r[i] = n + 1;for(int j = 0; j < 31; j++){if((a[i] & (1LL << j)))t[j] = i;else r[i] = min(r[i], t[j]);}}for(int i = 1; i <= n; i++){//cout << l[i] <<"~"<< i << "~"<< r[i] << endl;ans -= (i - l[i]) * (r[i] - i);}ans += n * (n + 1LL) / 2LL;printf("%lld\n", ans);return 0; }轉載于:https://www.cnblogs.com/Yumesenya/p/7679685.html
總結
以上是生活随笔為你收集整理的CF876 F 思维 枚举的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android junit单元测试
- 下一篇: ACM训练计划建议(转)