1. 程式人生 > >序列子區間問題(西安電子科技大學第16屆程式設計競賽 E Xieldy And His Password,U14739 X ask Y III 子區間異或和、牛客練習賽16 E求值)

序列子區間問題(西安電子科技大學第16屆程式設計競賽 E Xieldy And His Password,U14739 X ask Y III 子區間異或和、牛客練習賽16 E求值)

序列子區間問題一般都是問你,求序列子區間的和的和...異或和的和..和的異或和...和是3的倍數的個數...

這類問題一般都是用(字首和+)記錄狀態的陣列來實現,將O(n*n)的複雜度降為O(k*n)(k為常數)

這類問題可以從如何優化遍歷以i為結尾的連續子序列的複雜度為切入點,將O(n)->O(k)

題意:給你一個串,只由0,1組成,問你該串的子串表示的二進位制數是3的倍數的個數(0也是3的倍數,且允許有前導0)

解析:

如果一個二進位制數某一位是1,那麼它表示2^k,那麼2^k%3一定=1 or 2

並且一個二進位制數,奇數位(從0開始)上的1一定%3=2,偶數位(從0開始)上的1%3=1

這裡一個數要是3的倍數,那麼一個偶數位上的1就對應一個奇數位上的1來抵消,

那麼這個其實意味著一個1出現在某一位上,那麼一定要有一位1跟他相鄰偶數位,這樣才能抵消它,使得是3的倍數

這樣我們就可以一開始就把他按照奇偶位賦值(奇位1,偶位2),一旦num[i]=2,那麼前面一定要一個與它相鄰偶數位的1,即前面有一奇數位的1

同理num[i]=1,那麼前面一定要有一個偶數位的1來抵消它(那麼其實奇位2,偶位1也是可以的,兩個位置上的數只要互補就可以了)

那麼我們就用cnt[]記錄當前時刻,前面字首和%3=0,1,2的相應的個數(不包括當前時刻),

那麼我們在遍歷到i時,只要看當前i的字首和%3的餘數tt,看cnt[]數組裡面有多少個字首區間值為tt的,

那麼相應減去這些字首區間,就是以i為結尾的滿足條件的區間的個數

#include <iostream>
#include<string>
#include<bits/stdc++.h>
#include<cstdio>
using namespace std;
 
string a;
#define N 1000006
int num[N];
int sum[N];
int cnt[4];
#define ll long long
int main()
{
   ios::sync_with_stdio(false);
   while(cin>>a){
      for(int i = 0;i<a.length();i++){  //在任意一個2進位制位上1,表示的2^k%3=1 or 2
         if(a[i]=='0')
            num[i+1] = 0;
        else{
           if(i%2)
           num[i+1] = 2;
           else
           num[1+i] = 1;
        }
      }
      memset(cnt,0,sizeof(cnt));
      ll ans = 0;
      for(int i = 0;i<a.length();i++){
            int n = num[i+1];
            sum[i+1] = (sum[i]+n)%3;
            int tt = sum[i+1];
            ans += cnt[tt];   //當前字首和%3為tt,所以前面只要有字首和%3為tt,就剛好減掉這個字首區間,就符合條件
            if(sum[i+1]==0)  //所以只要加上前面是tt的字首區間的個數,就可以了,並且這裡一定能保證求出來的區間是連續的子區間(以i結尾)
            ans++;      //同時i的字首區間滿足條件的話,還要加上去,因為只是不需要減的情況
            cnt[tt]++;   //這裡其實就是用cnt[]這個陣列優化了遍歷(以i結尾)子區間的過程,將O(n)的複雜度降為O(1)
      }
      cout<<ans<<endl;
   }
    return 0;
}

題意:

求所有子區間的異或和的和

解析:

這裡需要思考的時如何用狀態陣列來優化遍歷到一個點,往前查詢答案的過程

因為從值的本身來找狀態,無從下手,這裡是異或,那麼我們就可以從它的二進位制來下手

因為是子區間問題,我們要求字首和,這樣才能保證我們的區間是連續的

當遍歷到一個字首和a[i]時,我們需要把以i為結尾的區間的答案全部找出來

這裡我們就可以用到二進位制了,當a[i]的k位為1時,我們答案要加上2^k*zero[k],zero[k]表示前面字首區間值對應第k位為0的個數,因為只有與這些字首區間異或後,

結果中第k位才不為0,這樣才能將2^k這個值加到答案裡(a[i](k)為1的時候同理)

例如,i>j,sum[j]為j的字首異或和,sum[i]同理,sum[i](k)表示sum[i]的二進位制第k位

當sum[i](k)去遍歷前面的字首區間時,遍歷到sum[j]時,如果sum[i](k)=1,sum[j](k)=0,那麼[j+1,i]這個區間的異或和的第k位一定是1,這樣就可以往答案加上2^k

如果sum[i](k)=0,sum[j](k)=1,那麼這個區間的異或和的第k位一定是1,同樣可以往答案加上2^k

#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pi acos(-1.0)
#define ll long long
#define mod 20090717
#define C 0.5772156649
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define pii pair<int,int>

using namespace std;

const double g=10.0,eps=1e-12;
const int N=200000+10,maxn=200000+10,inf=0x3f3f3f3f;

ll a[N];
ll one[50],zero[50];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i],a[i]^=a[i-1];
    ll sum=0;
    for(int i=0;i<=n;i++) //
    {
        for(int j=0;j<30;j++)
        {
            if(((a[i]>>j)&1))//1
            {
                sum+=zero[j]*(1ll<<j);  //表示字首和a[i]的第j位1於前面的所有字首和異或之後,有幾個1(即前面對應位子0的個數)
                one[j]++;
            }
            else
            {
                sum+=one[j]*(1ll<<j);
                zero[j]++;
            }
        }
    }
    cout<<sum<<endl;
    return 0;
}
/********************
1 2
********************/

牛客練習賽16 E求值

題意:

給你一個序列,讓你找裡面的連續子序列的或的和x,問這個序列由多少個不同的x

真的是菜.....剛寫完這個系列的部落格,遇到這道題還不會,看了別人程式碼.....

同樣這裡只不過用了類似字首和的狀態標記陣列,該數組裡面存的是各個二進位制數位上最後一次出現在該數位的數的下標。

之後同樣的過程,在找以i為結尾的子序列的值的過程中,將O(n)降低為O(20)。!!!!!

這裡巧妙的地方是將數位按照出現在該數位的最後一個數字的下標來分類,

這樣可行的原因是當你計算完[i-1,i]的或的和,計算[i-2,i]的或和時,之前i-1的值肯定是要或上的,這樣就實現了優化

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAXN = 1e5+10;
const int MAX = 2e6+100;
const int N =20;
int a[MAXN];
int sq[N+1];
int pos[N+1];
bool vis[MAX];

bool cmp(int a,int b)  //將數位按照最後出現在該數位上的數字的下標排
{
    return pos[a]>pos[b];
}


int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);

    }
    memset(pos,0,sizeof(pos));
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<N;j++)
        {
            sq[j]=j;
        }
        sort(sq,sq+N,cmp);
        int k=a[i];
        vis[a[i]]=true;
        for(int j=0;j<N;j++)
        {
            if(pos[sq[j]]==0) break;
            k=k|(1<<sq[j]);
            if(pos[sq[j]]!=pos[sq[j+1]])
            {
                vis[k]=true;
            }
        }
        k=a[i];
        for(int j=0;j<N&&k;j++)
        {
            if(k&1) pos[j]=i;
            k=k>>1;
        }
    }
    int ans=0;
    for(int i=0;i<MAX;i++)
    {
        if(vis[i]) ans++;
    }
    printf("%d\n",ans);
    return 0;

}


相關推薦

序列區間問題(西安電子科技大學16程式設計競賽 E Xieldy And His PasswordU14739 X ask Y III 區間練習賽16 E)

序列子區間問題一般都是問你,求序列子區間的和的和...異或和的和..和的異或和...和是3的倍數的個數... 這類問題一般都是用(字首和+)記錄狀態的陣列來實現,將O(n*n)的複雜度降為O(k*n)(k為常數) 這類問題可以從如何優化遍歷以i為結尾的連續子序列的複雜

2018年北京資訊科技大學程式設計競賽暨ACM選拔賽 A-PUBG

題目連結:https://www.nowcoder.com/acm/contest/118/A本來想用記憶化搜尋的,搞了半天弄不出來,乾脆跑dijkstra搞搞吧。#include<bits/st

U14739 X ask Y III 區間

很多 display c++ space code ask lose eps 區間 題意:就是求所有子區間的異或和的和 題解:就是算每一位對結果的貢獻(最近好像遇到很多次這種題目),先前綴異或,從左向右掃記錄二進制前綴的1,0個數,xor[i]==xor[j]^1的時候就

西安電子科技大學16程式設計競賽 E Xieldy And His Password

題解: 每次儲存取模等於0,1,2的情況數,然後迭代更新。 程式碼: #include<bits/stdc++.h> using namespace std; #define ll long long const int maxn=1e6+5;

ACM訓練日記—4月21日(西安電子科技大學16程式設計競賽網路同步賽)

int n,m,q; int a[50005]; int mp[50005]; int vis[50005]; int main() {     priority_queue<int>h;     while(scanf("%d%d%d",&n,&m,&q)!

電子科技大學ACM趣味程式設計競賽第二場題解

A陰陽師?這遊戲沒有ssr! 題解: ans = sigma(1 - (1 - Pi/100)^ 2); 標程: #include <stdio.h> #include <stdlib.h> int main() {     int N,p;    

POJ 2287 Tian Ji -- The Horse Racing&&浙江科技學院十三程式設計競賽1006 田忌賽馬後傳(貪心)

思路:如果田忌最慢的比齊王最慢的快,或者田忌最快的比齊王最快的快,那麼就比,否則讓田忌最慢的和齊王最快的比。 #include<map> #include<queue> #in

福州大學十三程式設計競賽_重現

 Problem C 平行四邊形數 Accept: 71    Submit: 345 Time Limit: 2000 mSec    Memory Limit : 32768 KB  Problem Description 在一個平面內給定n個點,任意三個點不在同

世界一流大學一流學科(雙一流建設)——西安電子科技大學

部分轉自:https://www.dxsbb.com/news/43529.html   1、雙一流大學簡介 雙一流,即世界一流大學和世界一流學科,是繼985工程(39所)、211工程(112所+4所學校有兩個校區=116所)之後又一國家戰略,其中世界一流大學42所,名單由

Easy Problem(西安電子科技大學第二節程式設計新生賽A)

Easy Problem 題目傳送門 題目描述 構造一個無重複的只含有正奇數的數列,使得這個數列所有項之和不超過n。輸出所能構造的數列長度的最大值。 輸入描述: 多組資料,輸入以EOF結尾(不超過1e5組) 每行一個n(1<=n<=1e9) 輸出描述: 每行一個數表示

電子科技大學九屆ACM趣味程式設計競賽第二場(正式賽) 題解

A::魔王的直播 注意23:59之後是00:00即可,找出所有迴文字元,取最近. #include <bits/stdc++.h> using namespace std; bool check(int a,int b) { int c=a%10*

2018年北京信息科技大學程序設計競賽暨ACM選拔賽-B-precise math function

AI 計算 ac代碼 AS esc lag .com load des 題目描述 喜愛ACM的PBY同學遇到了一道數學難題,已知底數n,請你幫他準確的計算出結果a = nπ(n的π次方),結果保留小數點後x位。 輸入描述: 第一行是一個整數t,表示測試實例的

哈爾濱理工大學軟體與微電子學院程式設計競賽同步賽(高年級) E 小樂樂匹配字串 【最長公共序列

傳送門:https://ac.nowcoder.com/acm/contest/301/E   求最長公共子序列。 立個 flag 搞dp。   AC code: #include <cstdio> #include <iostream> #inc

華中農業大學程式設計大賽網路同步賽

Problem A: Little Red Riding Hood Description Once upon a time, there was a little girl. Her name was Little Red Riding Hood. One

哈爾濱理工大學軟體與微電子學院程式設計競賽同步賽(高年級)補題(補一下dp相關的)簡單的e題匹配字串

可以通過這些內容先了解一下dp 題目連結 //狀態定義就是每個子問題 //狀態轉移就是狀態與狀態之間的轉移式 #include<cstdio> #include<string> #include<iostream> #include<alg

“青軟杯”安徽科技學院程式設計大賽_非專業組

1299 Problem C C互質個數 C互質個數 Time Limit:1000MS  Memory Limit:65536K Total Submit:21 Accepted:8 Description 貝貝、妞妞和康康都長大了,如今,他們已屆小學畢業,老師給貝貝出了一道強化計算的題目,讓她做一大堆除

中南大學十一屆大學生程式設計競賽-COJ1904-精靈的交際網

Submit Page Summary Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 12 Solved: 2 Description 天才少女科學家Cicini

練習賽7 E 珂朵莉的數列(樹狀數組+爆long long解決方法)

src main stdin scanf return n) can print con https://www.nowcoder.com/acm/contest/38/E 題意: 思路: 樹狀數組維護。從大佬那裏學習了如何處理爆long long的方法

練習賽7 E 珂朵莉的數列

arc scanner print amp tar [] next ++ implement 珂朵莉的數列 思路: 樹狀數組+高精度 離散化不知道哪裏寫錯了,一直wa,最後用二分寫的離散化 哪位路過大神可以幫我看看原來的那個離散化錯在哪裏啊 通過代碼: im

練習賽10 E題 數列查找 (分塊思想 + 莫隊算法)

意義 blog str aps mes blank ref pair rem 題目鏈接 數列查找 考慮分塊然後跑莫隊, 設$c[i]$為$i$在當前維護的區間內出現的次數, $g[i]$為在當前維護的區間內有多少個數出現次數為$i$, $bg[i]$把出現次數分塊