日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

NOI2019省选模拟赛 第五场

發(fā)布時間:2024/4/17 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 NOI2019省选模拟赛 第五场 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

爆炸了QAQ

傳送門

\(A\) \(Mas\)的童年

這題我怎么感覺好像做過……我記得那個時候還因為沒有取\(min\)結(jié)果\(100\to 0\)……

因為是個異或我們肯定得按位考慮貢獻(xiàn)了

\(a\)做個前綴異或和,記為\(s_i\),那么就是要找到

\[\max_{j<i}\{s_j+(s_j\oplus s_i)\}\]

我們假設(shè)\(s_i\)\(k\)位為\(a\)\(s_j\)\(k\)位為\(b\)\(s_j+(s_j\oplus s_i)\)\(k\)位為\(c\)

然后分類討論\(a,b\)的取值

\[a=1,b=0\to c=1\]

\[a=1,b=1\to c=1\]

\[a=0,b=1\to c=2\]

\[a=0,b=0\to c=0\]

那么我們顯然可以按位貪心,如果\(s_i\)\(k\)位為\(1\),那么\(s_j\)的第\(k\)位無論取\(1\)還是取\(0\)都沒有關(guān)系。如果\(s_i\)\(k\)位為\(0\),那么如果在滿足之前的一堆限制的條件下(即之前可能有幾位也需要強(qiáng)制取\(1\)),\(s_j\)的第\(k\)位取\(1\)的數(shù)仍然存在的話,那么肯定是取\(1\)最優(yōu)。而且顯然如果不取\(1\),后面怎么取都不會更優(yōu)

所以有一個\(O(n^2)\)的做法,記一個\(vis_s\)表示是否存在\(s\)這幾位全為\(1\)的數(shù),然后處理完\(a_i\)之后暴力枚舉子集,把對應(yīng)的\(vis\)設(shè)為\(1\)就行了

所以我們成功優(yōu)化到了和暴力相同的復(fù)雜度……

我們換個思路,記\(pos_s\)表示“滿足\(s\)這幾位全為\(1\)的數(shù)中,最小的位置是哪個”,那么每一次判斷前面是否有某個數(shù)\(s\)這幾位全為\(1\)的時候只要比較一下\(pos_s\)\(i\)的大小就可以了。\(pos\)可以直接用類似高位前綴和的思路\(O(n\log n)\)搞出來

//minamoto #include<bits/stdc++.h> #define R register #define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i) #define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i) #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v) template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;} using namespace std; char buf[1<<21],*p1=buf,*p2=buf; inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;} int read(){R int res,f=1;R char ch;while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');return res*f; } char sr[1<<21],z[20];int C=-1,Z=0; inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} void print(R int x){if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;while(z[++Z]=x%10+48,x/=10);while(sr[++C]=z[Z],--Z);sr[++C]=' '; } const int N=(1<<20)+5; int a[N],pos[N],n,x,res; int main(){ // freopen("testdata.in","r",stdin); // freopen("testdata.out","w",stdout);n=read();fp(i,0,1048575)pos[i]=n+1;fp(i,1,n)a[i]=read()^a[i-1],cmin(pos[a[i]],i);fp(j,0,19)fd(i,1048575,0)if(i>>j&1)cmin(pos[i^(1<<j)],pos[i]);fp(i,1,n){x=0,res=0;fd(j,19,0)if(a[i]>>j&1^1){pos[x^(1<<j)]<=i?(x^=(1<<j),res+=(1<<(j+1))):0;}else res+=(1<<j);print(res);}return Ot(),0; }

\(B\) \(Z\)的家鄉(xiāng)

我永遠(yuǎn)討厭數(shù)據(jù)結(jié)構(gòu)題\(.jpg\)

如果我們記\(mx_u\)表示\(u\)這棵子樹里最大的標(biāo)號,那么\(u\)的子樹\(v\)的遍歷順序就是按\(mx_v\)從大到小排序之后的順序

我們可以記一個\(f_u\)表示\(u\)這個子樹中遍歷順序的對應(yīng)的值,那么\(f_u\)就是所有子樹的\(f_v\)排序之后合并起來,再加上自己的值。如果每次暴力往上跳,隨機(jī)數(shù)據(jù)下樹高和兒子個數(shù)都是期望\(O(\log n)\)的,可以\(AC\)

然而這里數(shù)據(jù)并不隨機(jī)

我們發(fā)現(xiàn)每一次加入點(diǎn)的過程都類似于\(LCT\)\(access\),而且只有\(access\)時候虛邊轉(zhuǎn)為實邊的那幾個地方需要更新答案

由虛邊轉(zhuǎn)為實邊,就是說這一棵子樹的遍歷順序要到最前面

我們可以維護(hù)一個\(splay\),對于每一個在\(LCT\)上父親邊由實邊轉(zhuǎn)為虛邊的點(diǎn),把它們在\(splay\)上整個子樹拆下來,然后重新插進(jìn)去,插進(jìn)去的時候使它們新的值最大

并不建議看代碼理解因為我的代碼已經(jīng)丑到自己都看不下去了

//minamoto #include<bits/stdc++.h> #define R register #define ll long long #define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i) #define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i) #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v) using namespace std; char buf[1<<21],*p1=buf,*p2=buf; inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;} int read(){R int res,f=1;R char ch;while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');return res*f; } char sr[1<<21],z[20];int C=-1,Z=0; inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} void print(R int x){if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;while(z[++Z]=x%10+48,x/=10);while(sr[++C]=z[Z],--Z);sr[++C]='\n'; } const int N=2e5+5,P=998244353,Base=257933,inv=612171754; inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;} inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;} inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;} int ksm(R int x,R int y){R int res=1;for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;return res; } int st[N],ss[N],bin[N],top,n; struct LCT{struct node{node *ch[2],*fa;int sz,tag,id;node(){}inline void ppd(R int x){sz+=x,tag+=x;}inline void pd(){if(tag)ch[0]->ppd(tag),ch[1]->ppd(tag),tag=0;}inline bool is(){return fa->ch[0]!=this&&fa->ch[1]!=this;}inline bool re(){return fa->ch[1]==this;}void update(){if(!is())fa->update();pd();}void rotate(){node *y=fa,*z=y->fa;int d=re();if(!y->is())z->ch[y->re()]=this;fa=z,ch[d^1]->fa=y,y->ch[d]=ch[d^1],ch[d^1]=y,y->fa=this;}}pool[N],*p[N],*null;int num;LCT(){null=&pool[num++],null->fa=null->ch[0]=null->ch[1]=null,null->sz=null->tag=null->id=0;}inline node *newnode(){pool[num].fa=pool[num].ch[0]=pool[num].ch[1]=null;return &pool[num++];}inline void Pre(R int n){fp(i,1,n)p[i]=newnode(),p[i]->id=i;}//指針別xjb指!//人工開個NULL! void splay(node *x){x->update();for(R node *y=x->fa,*z=y->fa;!x->is();y=x->fa,z=y->fa){if(!y->is())(x->re()^y->re())?x->rotate():y->rotate();x->rotate();}}void access(node *x){node *t=null;while(x!=null){node *now=t;while(now->ch[0]!=null)now->pd(),now=now->ch[0];st[++top]=now->id,ss[top]=now->sz;splay(x);x->ch[1]=t,t->fa=x,t=x,x=x->fa;}++t->tag,++t->sz;} }A; struct Splay{struct node{node *ch[2],*fa;int sz,res,id;inline bool re(){return fa->ch[1]==this;}inline bool is(){return fa->ch[0]!=this&&fa->ch[1]!=this;}void upd(){res=(ch[0]->res+1ll*id*bin[ch[0]->sz]+1ll*bin[ch[0]->sz+1]*ch[1]->res)%P;sz=ch[0]->sz+ch[1]->sz+1;}void rotate(){node *y=fa,*z=y->fa;int d=re();if(!y->is())z->ch[y->re()]=this;fa=z,ch[d^1]->fa=y,y->ch[d]=ch[d^1],ch[d^1]=y,y->fa=this,y->upd();}}pool[N],*null,*p[N],*S,*T,*rt;int num;Splay(){null=&pool[num++],null->fa=null->ch[0]=null->ch[1]=null,null->sz=null->res=null->id=0;}inline node *newnode(){pool[num].fa=pool[num].ch[0]=pool[num].ch[1]=null;return &pool[num++];}void Pre(R int n){fp(i,1,n)p[i]=newnode(),p[i]->id=i,p[i]->sz=1,p[i]->res=i;S=newnode(),T=newnode(),rt=S,S->sz=T->sz=1;S->ch[1]=T,T->fa=S,T->upd(),S->upd();}//指針別xjb指!//人工開個NULL! void splay(node *x,node *c){if(c==null)rt=x;for(R node *y=x->fa;x->fa!=c;y=x->fa){if(y->fa!=c)(x->re()^y->re())?x->rotate():y->rotate();x->rotate();}x->upd();}node *get(int x){node *now=rt;while(now!=null){int sz=now->ch[0]->sz+1;if(sz==x)return now;else if(sz>x)now=now->ch[0];else now=now->ch[1],x-=sz;}}int rk(int x){splay(p[x],null);return p[x]->ch[0]->sz+1;}void insert(node *x,int k){node *t1=get(k+1),*t2=get(k+2);splay(t1,null),splay(t2,t1);t2->upd(),t1->upd();t2->ch[0]=x,x->fa=t2,t2->upd(),t1->upd();}inline int calc(){return mul(rt->res,inv);}void solve(){fd(i,top,3){int tr=rk(st[i]),tl=tr-ss[i];node *cl=get(tl),*cr=get(tr+1);splay(cl,null),splay(cr,cl);node *tmp=cr->ch[0];tmp->fa=cr->ch[0]=null;cr->upd(),cl->upd(),insert(tmp,0);}} }B; int x; int main(){ // freopen("testdata.in","r",stdin);n=read(),bin[0]=1;fp(i,1,n+2)bin[i]=mul(bin[i-1],Base);A.Pre(n),B.Pre(n),B.insert(B.p[1],0);fp(i,2,n){top=0,x=read(),A.p[i]->fa=A.p[x],A.access(A.p[i]);B.solve();B.insert(B.p[i],0);print(B.calc());}return Ot(),0; }

\(C\) 戰(zhàn)棋游戲

做一道題學(xué)一大堆的經(jīng)歷不管什么時候都是很有趣的呢……

前置芝士

環(huán)的染色方案數(shù)

我們現(xiàn)在要對一個環(huán)進(jìn)行染色,要求兩兩顏色不同,設(shè)點(diǎn)的個數(shù)為\(n\),顏色個數(shù)為\(c\),求方案數(shù)

設(shè)\(f_i\)表示\(i\)個點(diǎn)的染色方案數(shù)。我們可以欽定一個開頭,設(shè)為\(1\),并順時針一次記為\(2,3,...,n\)

如果\(1\)號點(diǎn)和\(n-1\)號點(diǎn)顏色不同,那么方案數(shù)為\(f_{n-1},\)\(n\)號點(diǎn)可以選的方案數(shù)就是\((c-2)\)

如果\(1\)號點(diǎn)和\(n-1\)號點(diǎn)顏色相同,那么方案數(shù)為\(f_{n-2}\),即等價于\(n-2\)個點(diǎn)的環(huán)再插一個進(jìn)去,此時\(n\)號點(diǎn)的顏色方案數(shù)為\(c-1\)

所以我們可以求得遞推公式

\[f_n=(c-2)f_{n-1}+(c-1)f_{n-2}\]

初值為\(f_0=1,f_1=c\)

根據(jù)數(shù)列的特征方程(因為我數(shù)學(xué)課老師講這個的時候我快睡著了所以我也不是很清楚所以具體百度),我們可以求得\(f_n\)的通項公式為

\[f_n=(c-1)^n+(-1)^n(c-1)\]

如果強(qiáng)制環(huán)的兩個端點(diǎn)相同的話,方案顯然就是\(f_{n-1}\)

\(O(n^2)\)多項式\(Ln\)和多項式\(Exp\)

其實這里是可以\(O(n\log n)\)搞的然而代碼實在太長而,且這里數(shù)據(jù)范圍夠小所以我們可以\(O(n^2)\)做,如果您耐心夠好而且對自己的多項式碼力有自信完全可以跳過這一節(jié)

經(jīng)過\(shadowice\)巨巨一個下午的調(diào)教我終于會了

對于多項式\(Ln\),我們需要暴力的就是它求逆的過程,即我們需要暴力計算一個形如

\[F(x)={P(x)\over Q(x)}\]

的柿子

根據(jù)\(Ln\)的使用條件,得有\([x^0]Q(x)=1\)

我們令\(T(x)=Q(x)-1\),則\(Q(x)=T(x)+1\),即

\[F(x)={P(x)\over T(x)+1}\]

\[F(x)(T(x)+1)=P(x)\]

\[F(x)=P(x)-F(x)T(x)\]

因為有\([x^0]T(x)=0\),所以我們就可以直接暴力卷積把\(F(x)\)給一項一項卷出來了,卷完之后積分一下就可以求出\(Ln\)

然后是多項式\(Exp\),即要求

\[F(z)=e^{G(z)}\]

\[F'(z)=G'(z)F(z)\]

沒了

題解

我們很明顯可以以騎士為關(guān)鍵點(diǎn)拆成若干部分,那么不同部分之間就是條鏈,影響方案數(shù)的只有兩個端點(diǎn)顏色是否相同了

ps:我們代碼里預(yù)處理的方案數(shù)沒有算上兩個端點(diǎn)的方案,所以兩端相同的方案要除以\(c\),兩端不同的方案要除以\(c(c-1)\)

我們\(2^k\)爆搜集合,表示強(qiáng)制\(s\)中的所有點(diǎn)為相同顏色,看看是否合法,如果合法的話記錄總的貢獻(xiàn)(即每一個點(diǎn)到它對應(yīng)的下一個點(diǎn)的那條鏈上的方案數(shù))

然后我們集合并卷積一下,求出\(f_{s,i}\)表示只允許\(s\)這個集合中有相同的顏色,且欽定的顏色相同的點(diǎn)的個數(shù)為\(i\)的總貢獻(xiàn)

我們把\(f_s\)看成一個多項式,那么\({f_{s}}^c\)就代表選\(c\)種顏色的方案數(shù),它的第\(k\)項就是總的方案

然而顯然這樣會算上一些不合法的情況,所以我們還得對\(s\)進(jìn)行一個容斥

代碼全是抄\(std\)的,因為這代碼實在是太難寫了我根本寫不下去……

//minamoto #include<bits/stdc++.h> #define R register #define ll long long #define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i) #define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i) #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v) using namespace std; const int N=25,M=(1<<20)+5,P=1e9+7; inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;} inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;} inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;} int ksm(R ll x,R ll y){R int res=1;x%=P;for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;return res; } int sz[M],f[M][N],same[N],diff[N],num[N],pos[N],g[N],h[N],inv[N],mp[N][N],vis[M],lg[M]; ll n,c,len,a[N];int k,m,iv,lim,res; inline bool cmp(const int &x,const int &y){return a[x]<a[y];} int main(){ // freopen("testdata.in","r",stdin);scanf("%lld%d%d%lld",&n,&k,&m,&c),c%=P,iv=ksm(c,P-2),lim=(1<<k);fp(i,0,k-1)scanf("%lld",&a[i]),num[i]=i;sort(num,num+k,cmp);fp(i,0,k-1){pos[num[i]+1]=i,len=a[num[(i+1)%k]]-a[num[i]];if(i==k-1)len+=n;if(len&1){same[i]=mul(iv,dec(ksm(c-1,len),c-1)),diff[i]=mul(iv,add(ksm(c-1,len),1));}else{same[i]=mul(iv,add(ksm(c-1,len),c-1)),diff[i]=mul(iv,dec(ksm(c-1,len),1));}}for(R int i=1,u,v;i<=m;++i)scanf("%d%d",&u,&v),mp[pos[u]][pos[v]]=mp[pos[v]][pos[u]]=1;vis[0]=1,f[0][0]=1;for(R int i=2;i<lim;i<<=1)lg[i]=lg[i>>1]+1;fp(s,1,lim-1){vis[s]=1,sz[s]=sz[s>>1]+(s&1);int u=lg[s&-s];if(!vis[s^(s&-s)]){vis[s]=0;continue;}fp(v,u+1,k-1)if(s>>v&1)vis[s]&=!mp[u][v];if(!vis[s])continue;f[s][sz[s]]=1;fp(i,0,k-1)if(s>>i&1){int v=(i+1)%k;f[s][sz[s]]=mul(f[s][sz[s]],(s>>v&1)?same[i]:diff[i]);}}for(R int i=1;i<lim;i<<=1)for(R int j=0;j<lim;j+=(i<<1))fp(l,0,i-1)fp(s,0,k)f[i+j+l][s]=add(f[i+j+l][s],f[j+l][s]);inv[0]=inv[1]=1;fp(i,2,k)inv[i]=mul(P-P/i,inv[P%i]);fp(s,0,lim-1){fp(i,0,k)h[i]=f[s][i];--h[0];fp(i,0,k){g[i]=0;fp(j,0,i)g[i]=add(g[i],mul(h[i-j],g[j]));g[i]=dec(mul(h[i+1],i+1),g[i]);}fd(i,k,1)g[i]=mul(g[i-1],inv[i]);g[0]=0;fp(i,1,k)g[i]=mul(g[i],c);fp(i,1,k)g[i-1]=mul(g[i],i);g[k]=0;h[0]=1;fp(i,0,k-1){int res=0;fp(j,0,i)res=add(res,mul(g[i-j],h[j]));h[i+1]=mul(res,inv[i+1]);}((k-sz[s])&1)?res=dec(res,h[k]):res=add(res,h[k]);}printf("%d\n",res);return 0; }

轉(zhuǎn)載于:https://www.cnblogs.com/bztMinamoto/p/10634601.html

總結(jié)

以上是生活随笔為你收集整理的NOI2019省选模拟赛 第五场的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。