NOI2014 部分題解

感受NOI2014的一些題目也是比較好作的...php

可是筆者每每有思路卻沒有想清楚就開始搞了...這樣仍是不太好..html

 

Day1數組

T1 起牀困難綜合徵  (我感受這題應該叫綜合徵不是綜合症...)   ac通道dom

讓你從[0...m]中選一個數使得其通過 (&xi或|xi或^xi) 以後的值最大。ide

記得冬令營有道試機題好像就是這樣吧...而後機智的TB感受十分天然的就想到了根據二進制的每一位來貪心弄一下就行了。spa

大體思路就是:從最高位開始,看一下這一位設爲0和設爲1有什麼區別。3d

若是無論你設什麼這一位運算完以後都爲0或者爲1,那就真·無論了...指針

若是發現設爲1有值而設爲0沒有值,那就設爲1吧。可是這個值不能超過m...rest

很機智的樣子。code

#include<cstdio> #include<cstring> #include<algorithm>
 
using namespace std; inline int in(){ int x=0;char ch=getchar(); while(ch>'9' || ch<'0') ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } const int maxn=100010; struct Node{ int tp,dt; }s[maxn]; int n,m; char ord[4]; int calcu(int x){ int tx=x; x=1<<x; for(int i=1;i<=n;i++){ if(s[i].tp==1) x=x&s[i].dt; else if(s[i].tp==2) x=x|s[i].dt; else x=x^s[i].dt; } return x&(1<<tx); } int main(){ #ifndef ONLINE_JUDGE freopen("sleep.in","r",stdin); freopen("sleep.out","w",stdout); #endif n=in(),m=in(); for(int i=1;i<=n;i++){ scanf("%s%d",ord,&s[i].dt); if(ord[0]=='A') s[i].tp=1; else if(ord[0]=='O') s[i].tp=2; else s[i].tp=3; } int ans=0; int tmp=0; for(int i=1;i<=n;i++){ if(s[i].tp==1) tmp=tmp&s[i].dt; else if(s[i].tp==2) tmp=tmp|s[i].dt; else tmp=tmp^s[i].dt; } for(int i=30;i>=0;i--){ if(tmp & (1<<i)){ ans+=1<<i; continue; } if(calcu(i) && m>(1<<i)) ans+=1<<i,m-=(1<<i); } printf("%d",ans); return 0; }
View Code



T2 魔法森林 ac通道

給你n個點m條邊,每條邊有2個權值,而後要求找一條路從1到n使得這條路上的兩個權值的最大值加起來最小。

我記得寫過一篇題解的...

而後就是複習一遍LCT的實現咯。

#include<cstdio> #include<cstring> #include<algorithm>
 
using namespace std; inline int in(){ int x=0;char ch=getchar(); while(ch>'9' || ch<'0') ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } const int maxn=100010; struct Node{ int l,r,f; int dt,mx,lc; bool rt,rv; Node(){rt=true;} void trans(){swap(l,r);} }s[maxn*3]; struct Edge{ int u,v,a,b; }e[maxn]; bool cmp(const Edge &A,const Edge &B){ if(A.a!=B.a) return A.a<B.a; return A.b<B.b; } int n,m; int p[maxn*2]; void update(int x); void push_down(int x); void Down_tag(int x); void zig(int x); void zag(int x); void Splay(int x); void Access(int x); void Make_rt(int x); void Link(int u,int v); void Cut(int u,int v); int Find(int x); int main(){ #ifndef ONLINE_JUDGE freopen("forest.in","r",stdin); freopen("forest.out","w",stdout); #endif n=in(),m=in(); for(int i=1;i<=m;i++){ e[i].u=in(),e[i].v=in(),e[i].a=in(),e[i].b=in(); if(e[i].u==e[i].v) i--,m--; } int fx,fy,u,v,ans=0x3f3f3f3f; sort(e+1,e+m+1,cmp); for(int i=1;i<=n+m;i++) p[i]=i; for(int i=1;i<=n+m;i++) s[i].lc=i; for(int i=1;i<=m;i++){ u=e[i].u,v=e[i].v; fx=Find(u),fy=Find(v); if(fx!=fy){ s[i+n].dt=e[i].b; Link(u,i+n),Link(v,i+n); p[fx]=fy; } else{ Make_rt(u),Access(v),Splay(v); if(s[v].mx>e[i].b){ int t=s[v].lc-n; Cut(t+n,e[t].u),Cut(t+n,e[t].v); s[i+n].dt=e[i].b; Link(u,i+n),Link(v,i+n); } } if(Find(1)==Find(n)){ Make_rt(1);Access(n);Splay(n); ans=min(ans,s[n].mx+e[i].a); } } if(ans==0x3f3f3f3f) ans=-1; printf("%d",ans); return 0; } void update(int x){ s[x].mx=s[x].dt,s[x].lc=x; if(s[x].l && s[s[x].l].mx>s[x].mx) s[x].mx=s[s[x].l].mx,s[x].lc=s[s[x].l].lc; if(s[x].r && s[s[x].r].mx>s[x].mx) s[x].mx=s[s[x].r].mx,s[x].lc=s[s[x].r].lc; } void push_down(int x){ if(s[x].rv){ s[x].trans(); if(s[x].l) s[s[x].l].rv^=1; if(s[x].r) s[s[x].r].rv^=1; s[x].rv=0; } } void Down_tag(int x){ if(!s[x].rt) Down_tag(s[x].f); push_down(x); } void zig(int x){ int y=s[x].f;s[x].f=s[y].f; if(s[y].rt) s[x].rt=true,s[y].rt=false; else{ if(y==s[s[y].f].l) s[s[y].f].l=x; else s[s[y].f].r=x; } s[y].l=s[x].r; if(s[x].r) s[s[x].r].f=y; s[x].r=y,s[y].f=x; update(y); } void zag(int x){ int y=s[x].f;s[x].f=s[y].f; if(s[y].rt) s[x].rt=true,s[y].rt=false; else{ if(y==s[s[y].f].l) s[s[y].f].l=x; else s[s[y].f].r=x; } s[y].r=s[x].l; if(s[x].l) s[s[x].l].f=y; s[x].l=y,s[y].f=x; update(y); } void Splay(int x){ Down_tag(x); while(!s[x].rt){ int y=s[x].f; if(s[y].rt){ if(x==s[y].l) zig(x); else zag(x);} else{ int z=s[y].f; if(y==s[z].l){ if(x==s[y].l) zig(y),zig(x); else zag(x),zig(x);} else{ if(x==s[y].r) zag(y),zag(x); else zig(x),zag(x);} } } update(x); } void Access(int x){ for(int last=0;x;x=s[last=x].f){ Splay(x); s[s[x].r].rt=true; s[s[x].r=last].rt=false; update(x); } } void Make_rt(int x){ Access(x); Splay(x); s[x].rv=1; } void Link(int u,int v){ Make_rt(u); s[u].f=v; } void Cut(int u,int v){ Make_rt(u); Access(v); Splay(v); s[u].rt=true; s[u].f=s[v].f; s[v].l=s[v].f=0; } int Find(int x){ int r=x,pre; while(r!=p[r]) r=p[r]; while(r!=x) pre=p[x],p[x]=r,x=pre; return r; }
View Code

 

D2

T1 動物園 ac通道

給你一個串,讓你求每一個位置的知足不重複的相同前綴和後綴的個數。

唔,比較容易想到的就是一種模擬的方法。

每一個位置都沿着next指針日後跳,看能在i/2以前跳多少次。

可是這樣的話是很容易卡你的,好比aaaaaaaaaaa,讓你每次next都只跳一步= =這樣的話就變成n^2了。

而後比較好像到的就是我直接記憶化一下累加的結果。使用記憶化的話,你能夠只要跳到第一個知足條件的位置就能夠了。

可是你跳到i/2前面的過程若是仍然使用模擬的話就會超時,理由同上。那麼怎麼求呢?

筆者太傻了...沒有想到直接沿着上一個的位置來就行了...和你求kmp的過程是徹底同樣的,只是這個的前引指針不是指向最長位置了,而是<i/2的最長位置。

而後你後面的指針日後移動的時候,前面的指針仍是能夠和之前的同樣跳。這樣的話就是O(n)的了。

感受對kmp的思路比較清晰的話對這題是頗有幫助的。

#include<cstdio>
#include<cstring>
#include<algorithm>
 
using namespace std;
 
typedef long long ll;
const int maxn=1000010;
const int mod=1e9+7;
 
int n,len;
int next[maxn],cnt[maxn];
char ch[maxn];
 
void get_next(){
    int first=-1,last=0;
    next[0]=-1;
    while(last<len){
        if(first==-1 || ch[last]==ch[first]){
            first++,last++;
            next[last]=first;
            cnt[last]=cnt[first]+1;
        }
        else
            first=next[first];
    }
}
 
int get_cnt(){
    int ans=1,first=-1,last=0;
    while(last<len){
        if(first==-1 || ch[last]==ch[first]){
            first++,last++;
            while((first<<1)>last) first=next[first];
            ans=(ll)ans*(cnt[first]+1)%mod;
        }
        else
            first=next[first];
    }
    return ans;
}
 
int main(){
#ifndef ONLINE_JUDGE
    freopen("zoo.in","r",stdin);
    freopen("zoo.out","w",stdout);
#endif
 
    int tmp;
    ll ans;
 
    scanf("%d",&n);
    while(n--){
        scanf("%s",ch);
        len=strlen(ch);
        get_next();
        printf("%d\n",get_cnt());
    }
 
    return 0;
}
View Code

 

T2 隨機數生成器 ac通道

告訴你一種生成隨機數的方法,告訴你一種經過隨機數生成排列的方法。而後把這個排列扔在一個n*m的地圖上,讓你選擇一條從(1,1)到(n,m)的路徑,使得這條路徑上的數字從小到大排序以後獲得的字典序最小。

首先的那個部分能夠模擬= =。可是你須要控制好空間,好比說隨機數你就沒有必要求出來,直接用來搞排列之類的...而後你那個地圖也不要作出來,直接搞一個一維的挺好。

而後就到了怎麼找到這樣一條路徑了...感受貪心的思路很天然。筆者趁機來秀一下gif[第一次作題解動圖...可能沒怎麼畫的好QAQ]。

作了一個樣例的求法...是否是很良心啊....

好吧:樣例不良心,可是筆者良心2333333

大體的思路就是如此了,按從小到大的順序,選擇了以後將(1,1)到(x-1,y)的矩陣保留,把(x+1,y)到(n,n)的矩陣保留,剩餘的刪除。

而後直到只剩下一條通路爲止。

首先咱們要能找到每一個點所在的位置,因爲以前已經用了100MB了,那麼咱們最多再開一個...那就記錄一個lc[T[i]]=i;而後把i%m和/m處理好了。

可是怎麼把矩陣保留|刪除呢?...是否是要用二維樹狀數組呢?可是二維樹狀數組也會超時啊...由於你要進行斷定的話,那麼就比較噁心...每一個點都要判斷一下...就超時了

那麼咱們直接暴力修改就行了。

每行記錄一個能夠放的範圍l[i]和r[i],而後每找到一個能夠用的點就去暴力修改其它行的有關數據。

因爲須要修改的點只有n+m-1個,那麼每次修改的複雜度即便是O(n)的也只有n^2;而斷定是否合格每一個位置都是O(1)的。

最後複雜度仍是N^2的可是常數很大而已啦...

#include<cstdio>
#include<cstring>
#include<algorithm>
 
using namespace std;
 
inline int in(){
    int x=0;char ch=getchar();
    while(ch>'9' || ch<'0') ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}
 
const int maxn=5010;
typedef long long ll;
 
int n,m,nm,q;
int x0,a,b,c,d;
int T[maxn*maxn],rk[maxn*maxn];
int l[maxn],r[maxn];
 
int main(){
#ifndef ONLINE_JUDGE
    freopen("random.in","r",stdin);
    freopen("ramdom.out","w",stdout);
#endif
 
    int x,u,v,tmp,x1,y1,cnt=0;
    bool flag=0;
 
    x0=in(),a=in(),b=in(),c=in(),d=in();
    n=in(),m=in();
    nm=n*m;
    for(int i=1;i<=nm;i++) T[i]=i;
     
    x=x0;
    for(int i=1;i<=nm;i++){
        x=((ll)a*x%d*x%d+(ll)b*x%d+c)%d;
        tmp=T[i],T[i]=T[x%i+1],T[x%i+1]=tmp;
        //swap(T[i],T[x%i+1]);
    }
     
    q=in();
    for(int i=1;i<=q;i++){
        u=in(),v=in();
        tmp=T[u],T[u]=T[v],T[v]=tmp;
        //swap(T[u],T[v]);
    }
    for(int i=1;i<=nm;i++) rk[T[i]]=i;
    for(int i=1;i<=n;i++) l[i]=1,r[i]=m;
    for(int i=1;i<=nm;i++){
        x1=rk[i]/m+1,y1=rk[i]%m;
        if(!y1) x1--,y1=m;
         
        if(y1>r[x1] || y1<l[x1]) continue;
        else{
            if(flag) printf(" %d",i);
            else flag=1,printf("%d",i);
             
            for(int j=1;j<x1;j++) if(r[j]>y1) r[j]=y1;
            for(int j=x1+1;j<=n;j++) if(l[j]<y1) l[j]=y1;
            cnt++;
            if(cnt==n+m-1) break;
        }
    }
     
    return 0;
}
View Code
相關文章
相關標籤/搜索