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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Codeforces Round #556 (Div. 1)

發(fā)布時間:2023/12/1 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Codeforces Round #556 (Div. 1) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Codeforces Round #556 (Div. 1)

A. Prefix Sum Primes

給你一堆1,2,你可以任意排序,要求你輸出的數(shù)列的前綴和中質數(shù)個數(shù)最大。

發(fā)現(xiàn)只有\(2\)是偶質數(shù),那么我們先放一個\(2\),再放一個\(1\),接下來把\(2\)全部放掉再把\(1\)全部放掉就行了。

#include<iostream> #include<cstdio> using namespace std; inline int read() {int x=0;bool t=false;char ch=getchar();while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();if(ch=='-')t=true,ch=getchar();while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();return t?-x:x; } int n,a[3]; int main() {n=read();for(int i=1;i<=n;++i)a[read()]+=1;if(a[2]){printf("2 "),a[2]-=1;if(a[1])printf("1 "),a[1]-=1;}while(a[2])printf("2 "),a[2]-=1;while(a[1])printf("1 "),a[1]-=1;puts("");return 0; }

B. Three Religions

給你一個串\(S\),會動態(tài)的修改三個串,修改是在三個串的末尾刪去或加入一個字符。
每次修改完之后回答這三個串能否表示成\(S\)的三個不交的子序列。

考慮一個\(dp\)\(f[i][a][b][c]\),表示當前考慮到了串的第\(i\)個位置,匹配了到了三個串的\(a,b,c\)位置。
然后發(fā)現(xiàn)第一維這個東西非常蠢。把狀態(tài)改一下,變成\(f[a][b][c]\)表示三個串分別匹配到\(a,b,c\)\(i\)的最小值。
這樣子單次修改轉移的復雜度就是\(O(len^2)\),這樣子復雜度就很對了。

#include<iostream> #include<cstdio> using namespace std; #define MAX 100100 int n,Q; int nxt[MAX][26],lst[26]; char s[MAX],a[4][MAX]; int len[4],f[255][255][255]; void dp(int x,int y,int z) {if(!(x|y|z))return;f[x][y][z]=n+1;if(x&&f[x-1][y][z]<=n)f[x][y][z]=min(f[x][y][z],nxt[f[x-1][y][z]][a[1][x]-97]);if(y&&f[x][y-1][z]<=n)f[x][y][z]=min(f[x][y][z],nxt[f[x][y-1][z]][a[2][y]-97]);if(z&&f[x][y][z-1]<=n)f[x][y][z]=min(f[x][y][z],nxt[f[x][y][z-1]][a[3][z]-97]); } int main() {scanf("%d%d%s",&n,&Q,s+1);for(int i=0;i<26;++i)lst[i]=n+1;for(int i=n;~i;--i){for(int j=0;j<26;++j)nxt[i][j]=lst[j];if(i)lst[s[i]-97]=i;}while(Q--){char ch[2],ss[2];int x;scanf("%s%d",ch,&x);if(ch[0]=='+'){scanf("%s",ss);a[x][++len[x]]=ss[0];if(x==1)for(int i=0;i<=len[2];++i)for(int j=0;j<=len[3];++j)dp(len[1],i,j);if(x==2)for(int i=0;i<=len[1];++i)for(int j=0;j<=len[3];++j)dp(i,len[2],j);if(x==3)for(int i=0;i<=len[1];++i)for(int j=0;j<=len[2];++j)dp(i,j,len[3]);}else --len[x];if(f[len[1]][len[2]][len[3]]<=n)puts("YES");else puts("NO");}return 0; }

C. Tree Generator?

給你一個括號序列,顯然一個合法的括號序列和一棵樹是對應的。
現(xiàn)在每次交換括號序列的兩個位置,求交換完之后的每一棵樹的直徑。

首先問題可以變成給定把(看成\(1\),把)看成\(-1\)
于是問題就變成了你要在括號序列上找到任意一段連續(xù)的子串,并且把它分成兩段,使得后一半的值減去前一半的值最大。
然后線段樹維護一下就行了。

#include<iostream> #include<cstdio> using namespace std; #define MAX 200200 #define lson (now<<1) #define rson (now<<1|1) inline int read() {int x=0;bool t=false;char ch=getchar();while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();if(ch=='-')t=true,ch=getchar();while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();return t?-x:x; } int n,Q;char s[MAX]; struct Node{int pre[2],suf[2],ans,sum,tot;}t[MAX<<2],L,R; Node operator+(Node a,Node b) {Node c;c.pre[0]=max(a.pre[0],a.sum+b.pre[0]);c.pre[1]=max(a.pre[1],max(a.tot+b.pre[0],-a.sum+b.pre[1]));c.suf[0]=max(b.suf[0],-b.sum+a.suf[0]);c.suf[1]=max(b.suf[1],max(b.tot+a.suf[0],b.sum+a.suf[1]));c.sum=a.sum+b.sum;c.tot=max(a.tot+b.sum,-a.sum+b.tot);c.ans=max(max(a.ans,b.ans),max(a.suf[0]+b.pre[1],a.suf[1]+b.pre[0]));return c; } void Modify(int now,int l,int r,int p) {if(l==r){t[now]=(s[p]=='(')?L:R;return;}int mid=(l+r)>>1;if(p<=mid)Modify(lson,l,mid,p);else Modify(rson,mid+1,r,p);t[now]=t[lson]+t[rson]; } int main() {L=(Node){1,1,0,1,1,1,1};R=(Node){0,1,1,1,1,-1,1};n=(read()-1)<<1;Q=read();scanf("%s",s+1);for(int i=1;i<=n;++i)Modify(1,1,n,i);printf("%d\n",t[1].ans);while(Q--){int x,y;swap(s[x=read()],s[y=read()]);Modify(1,1,n,x);Modify(1,1,n,y);printf("%d\n",t[1].ans);}return 0; }

D. Abandoning Roads

你有一張圖,你需要對于每一個點回答在任意一棵最小生成樹中,\(1\)號點到這個點的路徑的最小值是多少。
邊權只有兩種。

首先小的邊權叫做\(a\),大的邊權叫做\(b\)
現(xiàn)在是\(a\)邊構成了一堆聯(lián)通塊,然后你用\(b\)邊把這些聯(lián)通塊鏈接然后求最短路。
這里直接求最短路有一個問題就是你不能在同一個聯(lián)通塊內用\(b\)邊,也不能讓一條路徑重復的經(jīng)過兩次同一個聯(lián)通塊。
那么我們考慮狀壓,記錄已經(jīng)訪問過了哪一些聯(lián)通塊。
然而這樣子是\(2^n\)的。
發(fā)現(xiàn)大小為\(1,2,3\)的聯(lián)通塊你不可能用\(b\)邊繞一圈再重新進來,所以只需要考慮大小至少為\(4\)的聯(lián)通塊。這樣子復雜度就降下來了

#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; #define MAX 72 inline int read() {int x=0;bool t=false;char ch=getchar();while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();if(ch=='-')t=true,ch=getchar();while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();return t?-x:x; } struct Line{int v,next,w;}e[500]; int h[MAX],cnt=1; inline void Add(int u,int v,int w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;} int f[MAX],sz[MAX]; int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);} void Merge(int x,int y){x=getf(x);y=getf(y);f[y]=x;sz[x]+=sz[y];} int dis[MAX][131072];bool vis[MAX][131072]; struct Node{int u,d,S;}; bool operator<(Node a,Node b){return a.d>b.d;} priority_queue<Node> Q; void upd(int u,int d,int S){if(dis[u][S]>d)dis[u][S]=d,Q.push((Node){u,d,S});} int n,m,A,B,book[MAX],tim; int main() {n=read();m=read();A=read();B=read();for(int i=1;i<=n;++i)f[i]=i,sz[i]=1,book[i]=-1;for(int i=1;i<=m;++i){int u=read(),v=read(),w=read();Add(u,v,w);Add(v,u,w);if(w==A)Merge(u,v);}for(int i=1;i<=n;++i)if(book[i]==-1&&sz[getf(i)]>3){for(int j=i;j<=n;++j)if(getf(i)==getf(j))book[j]=tim;++tim;}memset(dis,63,sizeof(dis));upd(1,0,(~book[1])?1<<book[1]:0);while(!Q.empty()){int u=Q.top().u,S=Q.top().S;Q.pop();if(vis[u][S])continue;vis[u][S]=true;for(int i=h[u];i;i=e[i].next){int v=e[i].v,w=e[i].w;if(w==A)upd(v,dis[u][S]+w,S);else{if(getf(u)==getf(v))continue;if(~book[v]&&(S&(1<<book[v])))continue;upd(v,dis[u][S]+w,S|((~book[v])?1<<book[v]:0));}}}for(int i=1;i<=n;++i){int ans=1<<30;for(int j=0;j<1<<tim;++j)ans=min(ans,dis[i][j]);printf("%d ",ans);}return 0; }

E. Election Promises

有一個\(DAG\),現(xiàn)在兩個人輪流操作。每次操作可以隨意指定一個權值不為\(0\)的點,然后把它的權值減小為任意非負整數(shù),同時可以把其所有出邊的點權任意修改。不能操作者輸。
求先手是否必勝。

首先盲猜肯定和\(sg\)函數(shù)那套理論相關,然后把每個點的\(sg\)值給求出來。
題目的結論是:對于所有\(sg=i\)的點,我們令\(s_k=\oplus_{sg[i]=k}h[i]\),如果存在一個\(s_k\neq 0\)的話那么先手必勝,否則先手必敗。

證明(偽證)
首先\(h\)全是\(0\)的時候一定是先手必敗。
對于一個\(sg=k\)的點\(u\),其兒子中必定包含了\([0,k-1]\)這些\(sg\)值。那么我們找到最大的\(sg\)值,其一定只能影響所有比他小的\(sg\)值的位置。
那么我們修改這個\(sg\)值中\(h\)最大的那個點,那么必定可以讓它的\(sg\)值減小,然后一定可以把所有的\(s\)全部變成\(0\),于是我們變成了一個必敗態(tài)。
而后手此時操作完之后又一定存在至少一個數(shù)是\(0\),又成了必勝態(tài)。

#include<iostream> #include<cstdio> #include<vector> using namespace std; #define MAX 200200 inline int read() {int x=0;bool t=false;char ch=getchar();while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();if(ch=='-')t=true,ch=getchar();while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();return t?-x:x; } vector<int> E[MAX]; int n,m,h[MAX],sg[MAX],sum[MAX]; int dg[MAX],Q[MAX],vis[MAX]; void Topsort() {int h=1,t=0;for(int i=1;i<=n;++i)if(!dg[i])Q[++t]=i;while(h<=t){int u=Q[h++];for(int v:E[u])if(!--dg[v])Q[++t]=v;} } int main() {n=read();m=read();for(int i=1;i<=n;++i)h[i]=read();for(int i=1;i<=m;++i){int u=read(),v=read();E[u].push_back(v);++dg[v];}Topsort();for(int i=n;i;--i){int u=Q[i];for(int v:E[u])vis[sg[v]]=i;while(vis[sg[u]]==i)++sg[u];sum[sg[u]]^=h[u];}for(int i=n;~i;--i)if(sum[i]){int pos;for(int j=1;j<=n;++j)if(sg[j]==i&&h[j]>(sum[i]^h[j]))pos=j;h[pos]^=sum[i];for(int v:E[pos])h[v]^=sum[sg[v]],sum[sg[v]]=0;puts("WIN");for(int j=1;j<=n;++j)printf("%d ",h[j]);puts("");return 0;}puts("LOSE");return 0; }

轉載于:https://www.cnblogs.com/cjyyb/p/10802497.html

總結

以上是生活随笔為你收集整理的Codeforces Round #556 (Div. 1)的全部內容,希望文章能夠幫你解決所遇到的問題。

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