Codeforces 1198 1199
1198 D
你需要維護一個序列,支持兩種操作:
- 對于 \(1\le i\le n\) , \(a[i] \leftarrow \max(a[i],x)\) ;
- 對于給定的 \(p\) , \(a[p] \leftarrow x\) 。
\((1\le n,Q\le 2*10^5)\)
Examples
input
4
1 2 3 4
3
2 3
1 2 2
2 1
output
3 2 3 4
input
5
3 50 2 1 10
3
1 2 0
2 8
1 3 20
output
8 8 20 8 10
解
線段樹。
Code
#include<bits/stdc++.h> using namespace std; const int maxn=200003; struct node{int val,z; }t[maxn<<2]; int n,Q; void pushdown(int p,int l,int r){if(l==r){t[p].val=max(t[p].val,t[p].z),t[p].z=0;return;}t[p<<1].z=max(t[p<<1].z,t[p].z);t[p<<1|1].z=max(t[p<<1|1].z,t[p].z);t[p].z=0; } void build(int p,int l,int r){if(l==r){scanf("%d",&t[p].val);return;}int mid=(l+r)>>1;build(p<<1,l,mid);build(p<<1|1,mid+1,r); } void change(int p,int l,int r,int pos,int k){pushdown(p,l,r);if(l==r){t[p].val=k;return;}int mid=(l+r)>>1;if(pos<=mid)change(p<<1,l,mid,pos,k);else change(p<<1|1,mid+1,r,pos,k); } int query(int p,int l,int r,int pos){pushdown(p,l,r);if(l==r)return t[p].val;int mid=(l+r)>>1;if(pos<=mid)return query(p<<1,l,mid,pos);else return query(p<<1|1,mid+1,r,pos); } int main(){scanf("%d",&n);build(1,1,n);scanf("%d",&Q);int mo,x,y;while(Q--){scanf("%d%d",&mo,&x);if(mo==1){scanf("%d",&y);change(1,1,n,x,y);}else{pushdown(1,1,n);t[1].z=x;}}for(int i=1;i<=n;i++)printf("%d ",query(1,1,n,i));return 0; }1199 E
給你一個 \(3*n\) 個節點 \(m\) 條邊的無向圖,如果存在一個匹配大小為 \(n\) 輸出這個匹配;否則如果存在一個獨立集大小為 \(n\) 輸出這個獨立集;否則輸出Impossible。\((n\le 10^5,m\le 5*10^5)\)
Example
input
4
1 2
1 3
1 2
1 2
1 3
1 2
2 5
1 2
3 1
1 4
5 1
1 6
2 15
1 2
1 3
1 4
1 5
1 6
2 3
2 4
2 5
2 6
3 4
3 5
3 6
4 5
4 6
5 6
output
Matching
2
IndSet
1
IndSet
2 4
Matching
1 15
解
先找出任意一個匹配,如果匹配大小 \(\geq n\) ,輸出;否則找出所有不在這個匹配中的節點,這些節點構成的集合一定是原圖的一個獨立集,輸出。不存在Impossible的情況。
證明:如果匹配大小 \(<n\) ,那么剩下的節點數量肯定 \(\geq n\) 。
Code
#include<bits/stdc++.h> using namespace std; const int maxn=500003; bool vis[maxn]; int n,m,ANS[maxn]; int main(){int T;scanf("%d",&T);while(T--){scanf("%d%d",&n,&m);for(int i=1;i<=3*n;i++)vis[i]=0;int CNT=0;for(int i=1;i<=m;i++){int u,v;scanf("%d%d",&u,&v);if(!vis[u]&&!vis[v]){vis[u]=vis[v]=1;ANS[++CNT]=i;}}if(CNT>=n){puts("Matching");for(int i=1;i<=n;i++)printf("%d%c",ANS[i],i<n?' ':'\n');}else{puts("IndSet");CNT=0;for(int i=1;i<=3*n;i++)if(!vis[i])ANS[++CNT]=i;assert(CNT>=n);for(int i=1;i<=n;i++)printf("%d%c",ANS[i],i<n?' ':'\n');}}return 0; }1199 F
有一個 \(n*n\) 的矩陣,有些位置是黑的,有些是白的,現在你有若干次染色機會,每次你可以選擇一個高為 \(h\) 寬為 \(w\) 的長方形,把其中的元素全染成白色,代價為 \(\max(h,w)\) 。求最小代價使得能把整個矩陣染成白色。 \((n\le 50)\)
Examples
input
3 ### #.# ###output
3input
3 ... ... ...output
0input
4 #... .... .... #...output
2input
5 #...# .#.#. ..... .#... #....output
5解
\(O(n^5)\;\text{dp}\) 。
Code
#include<bits/stdc++.h> using namespace std; const int maxn=53; int n,sum[maxn][maxn],dp[maxn][maxn][maxn][maxn]; char s[maxn][maxn]; int val(int ii,int jj,int i,int j){return sum[i][j]-sum[ii-1][j]-sum[i][jj-1]+sum[ii-1][jj-1]?max(i-ii+1,j-jj+1):0; } int main(){scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%s",s[i]+1);for(int j=1;j<=n;j++){sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+(s[i][j]=='#');}}for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){for(int ii=i;ii>=1;ii--){for(int jj=j;jj>=1;jj--){dp[ii][jj][i][j]=val(ii,jj,i,j);for(int k=ii;k<i;k++){dp[ii][jj][i][j]=min(dp[ii][jj][i][j],dp[ii][jj][k][j]+dp[k+1][jj][i][j]);}for(int k=jj;k<j;k++){dp[ii][jj][i][j]=min(dp[ii][jj][i][j],dp[ii][jj][i][k]+dp[ii][k+1][i][j]);}}}}}printf("%d\n",dp[1][1][n][n]);return 0; }1198 E
字符矩陣形式輸入變成兩個坐標輸入,兩個坐標之間的所有格子都是黑的;代價變為 \(\min(h,w)\) ; \(n\le 10^9\) ;其它同1199 F。
Examples
inputCopy
10 2
4 1 5 10
1 4 10 5
outputCopy
4
inputCopy
7 6
2 1 2 1
4 2 4 3
2 5 2 5
2 3 5 3
1 2 1 2
3 2 5 3
outputCopy
3
解
本題做法和上題風馬牛不相及。
首先肯定是一行一行或一列一列刪最優。
看到算法標簽有網絡流和二分圖匹配,于是想到經典的二分圖最小點覆蓋。
于是,先把所有區間的左端點值和右端點值+1離散化,設離散化數組為 \(mp[i]\) ,然后建二分圖,每個節點 \(i\) 代表區間 \([mp[i],mp[i+1])\) ,然后對于每個輸入中的矩形,把對應的節點連邊。本題不是普通的二分圖,所以推薦使用dinic跑。
Code
#include<cstdio> #include<algorithm> using namespace std; const int maxn=40003,maxm=400003,INF=1050000000; struct edge{int to,next,w;}e[maxm<<1]; int head[maxn],head1[maxn],cnte; void add(int u,int v,int w){e[++cnte].to=v,e[cnte].w=w,e[cnte].next=head[u],head[u]=cnte;} void addedge(int u,int v,int w){add(u,v,w),add(v,u,0);} int n,s,t,dep[maxn],q[maxn]; bool bfs(){for(int i=1;i<=n;i++)dep[i]=0,head1[i]=head[i];dep[s]=1;int *qhead=q,*qtail=q;*qtail++=s;while(qhead!=qtail){int u=*qhead++;for(int i=head[u];~i;i=e[i].next){int v=e[i].to;if(e[i].w&&dep[v]==0){dep[v]=dep[u]+1;*qtail++=v;}}}return dep[t]!=0; } int dfs(int u,int low){if(low==0||u==t)return low;int flow=0;for(int &i=head1[u];~i;i=e[i].next){int v=e[i].to;if(e[i].w&&dep[v]==dep[u]+1){int tmp=dfs(v,min(low,e[i].w));if(tmp==0)dep[v]=0;else{flow+=tmp;low-=tmp;e[i].w-=tmp;e[i^1].w+=tmp;if(low==0)break;}}}return flow; } int dinic(){int ans=0;while(bfs())ans+=dfs(s,INF);return ans; } int N,M,x1[maxn],x2[maxn],y1[maxn],y2[maxn],mp[maxn],cntmp; int main(){scanf("%d%d",&N,&M);for(int i=1;i<=M;i++){scanf("%d%d%d%d",x1+i,y1+i,x2+i,y2+i);x2[i]++,y2[i]++;mp[++cntmp]=x1[i],mp[++cntmp]=y1[i],mp[++cntmp]=x2[i],mp[++cntmp]=y2[i];}sort(mp+1,mp+cntmp+1);cntmp=unique(mp+1,mp+cntmp+1)-mp-1;s=cntmp*2+1,n=t=s+1;for(int i=1;i<=n;i++)head[i]=-1;cnte=-1;for(int i=1;i<=M;i++){x1[i]=lower_bound(mp+1,mp+cntmp+1,x1[i])-mp;y1[i]=lower_bound(mp+1,mp+cntmp+1,y1[i])-mp;x2[i]=lower_bound(mp+1,mp+cntmp+1,x2[i])-mp;y2[i]=lower_bound(mp+1,mp+cntmp+1,y2[i])-mp;for(int j=x1[i];j<x2[i];j++){for(int k=y1[i];k<y2[i];k++){addedge(j,k+cntmp,INF);}}}for(int i=1;i<cntmp;i++){addedge(s,i,mp[i+1]-mp[i]);addedge(i+cntmp,t,mp[i+1]-mp[i]);}printf("%d\n",dinic());return 0; }1198 F
有一個數組,現在你要把它分成兩部分,要求每部分的\(\gcd\)值為1。不可能輸出NO。 \((n\le 10^5)\)
Examples
input
4
2 3 6 7
output
YES
2 2 1 1
input
5
6 15 35 77 22
output
YES
2 1 2 1 1
input
5
6 10 15 1000 75
output
NO
解
看代碼,你的嘴巴會張大
Code
#include<bits/stdc++.h> using namespace std; typedef pair<int,int> P; const int maxn=100003; int n,b[maxn]; P a[maxn]; int main(){srand(19260817);scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i].first),a[i].second=i;while(double(clock())/CLOCKS_PER_SEC<0.47){random_shuffle(a+1,a+n+1);int g1=0,g2=0;for(int i=1;i<=n;i++){if(rand()&1){if(!g1)g1=a[i].first,b[a[i].second]=1;else if(a[i].first%g1)g1=__gcd(g1,a[i].first),b[a[i].second]=1;else g2=__gcd(g2,a[i].first),b[a[i].second]=2;}else{if(!g2)g2=a[i].first,b[a[i].second]=2;else if(a[i].first%g2)g2=__gcd(g2,a[i].first),b[a[i].second]=2;else g1=__gcd(g1,a[i].first),b[a[i].second]=1;}}if(g1==1&&g2==1){puts("YES");for(int i=1;i<=n;i++)printf("%d ",b[i]);return 0;}}puts("NO");return 0; }轉載于:https://www.cnblogs.com/BlogOfchc1234567890/p/11284731.html
總結
以上是生活随笔為你收集整理的Codeforces 1198 1199的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [Spring cloud 一步步实现广
- 下一篇: 如何成长?