【Codeforces】Educational Codeforces Round 46(Contest 1000)
题目
传送门:QWQ
A:Codehorses T-shirts
题意:
给定一些字符串表示去年和今年的衣服型号大小( XL XXL M...... ),要求用最少的次数把去年的衣服大小改成今年需要的。每次改动只能更改字符,不能增添字符。
分析:
把今年和去年的型号字典序排一下。然后用挨个对上(因为题目保证合法,所以长度一样的数量必定相等)。在字符串长度是1的时候要暴力匹配一下,因为长度为1时有L S M三种东西。
代码:
#include <bits/stdc++.h> using namespace std; const int maxn=1200; string a[maxn], b[maxn], q1[maxn], q2[maxn]; int vis[maxn]; int main(){ int n; scanf("%d",&n); for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++) cin>>b[i]; sort(a+1,a+1+n);sort(b+1,b+1+n); int ans=0; for(int i=1;i<=n;i++){ if(a[i].length()==1) continue; for(int j=0;j<a[i].length();j++) { if(a[i][j]!=b[i][j]) ans++; } } int k=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ if(a[i].length()!=1||b[j].length()!=1) continue; if(a[i]==b[j] && vis[j]==0) { vis[j]=1; k--; break; } } for(int i=1;i<=n;i++) if(a[i].length()==1) k++; printf("%d\n",ans+k); return 0; }
B:Light It Up
题意:
给定一个$ 10^18 $ 次方的数轴,在数轴上有一些点表示时间。其中有端点0和M。随着时间的推移,每到一个时间点就改变等的状态。
你可以新插入一个点(或者不插),求插入后总的灯亮的时间。
分析:
显然我插的点肯定是在给的点左一个或右一个·。然后前缀和优化模拟一下。
代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1000005; ll A1[maxn],A2[maxn]; ll M[maxn],maxans;ll sum=0; int main(){ int n;ll m;scanf("%d%I64d",&n,&m); memset(A1,0,sizeof(A1));memset(A2,0,sizeof(A2));memset(M,0,sizeof(M)); M[1]=0;M[n+2]=m; for(int i=2;i<=n+1;i++){ scanf("%I64d",&M[i]); } M[n+3]=M[n+2]; for(int i=1;i<=n+2;i+=2){ A1[i-1]=A1[i-2]; A1[i]+=A1[i-2]+M[i+1]-M[i]; }A1[n+2]=A1[n+1]; for(int i=2;i<=n+2;i+=2){ A2[i-1]=A2[i-2]; A2[i]+=A2[i-2]+M[i+1]-M[i]; } A2[n+2]=A2[n+1]; for(int i=1;i<=n+2;i++){ ll ma1,ma2; if(i%2==1 && M[i]!=M[i-1]+1){ ma1=A1[i-1]-1+(A2[n+2]-A2[i-1]); ma2=A1[i]-1+(A2[n+2]-A2[i-1]); } else if(M[i]!=M[i+1]-1){ ma1=A1[i-1]-1+(A2[n+2]-A2[i-1]); ma2=A1[i]-1+(A2[n+2]-A2[i-1]); } if(i!=1) maxans=max(maxans,max(ma1,ma2)); else maxans=ma2; } printf("%I64d\n",max(A1[n+2],maxans)); return 0; }
C:Covered Points Count
题意:
线段覆盖数轴相关
分析:
大力算一下,如果是左端点就ans++,否则ans--
代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=2000000; ll sum[maxn]; struct Node{ ll a;int type; bool operator < (const Node& b) const{return a<b.a;} }A[maxn]; int main(){ int n,cnt=0;scanf("%d",&n); ll l,r; for(int i=1;i<=n;i++){ scanf("%I64d%I64d",&l,&r); A[++cnt].a=l; A[cnt].type=1; A[++cnt].a=r+1; A[cnt].type=-1; } sort(A+1,A+1+cnt); A[0].a=A[1].a; int ans=0,preans=0; for(int i=1;i<=cnt;i++){ preans=ans; ans+=A[i].type; sum[preans]+=A[i].a-A[i-1].a; } for(int i=1;i<=n;i++){ printf("%I64d ",sum[i]); } return 0; } /* 5 10000000000 20000000000 10 100000000000000000 10 100000000000000000 10 100000000000000000 10 100000000000000000 */
D:Yet Another Problem On a Subsequence
题意:
如果一个数组$ a_1.......a_k $ 且 $ a_1 = k-1$,辣么这个数组就是好数组。
一个好序列由好序列和(或)好数组组成。
给出一序列,求他有多少子序列是好序列。
分析:
很显然想到组合数计数一下,但不好处理子序列这个问题。
用$ dp[i] $表示以i开头的好序列的数量
然后对于每个$ a[i] $更新$ dp $
代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=2000l;const ll MOD=998244353; ll C[maxn][maxn], a[maxn], dp[maxn]; int main(){ int n;scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%I64d",&a[i]); for(int i=1;i<=n+5;i++) for(int j=1;j<=n+5;j++){ if(j==1) C[i][j]=i; else C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD; } dp[n+1]=1; for(int i=n-1;i>=1;i--){ if(a[i]<=0 || a[i]+i>n) continue; for(int j=i+a[i]+1;j<=n+1;j++){ dp[i]=(dp[i]+C[j-i-1][a[i]]*dp[j])%MOD; } } ll ans=0; for(int i=1;i<=n;i++){ ans=(ans+dp[i])%MOD; } printf("%I64d\n",ans); return 0; }
E:We Need More Bosses
题意:
求一张图桥最多的路径上桥的数量
分析:
缩点后求树的直径
代码:
#include <bits/stdc++.h> using namespace std; const int maxn=2000005; struct Edge{ int u,v; }; vector<Edge> edges; vector<int> G[maxn], g[maxn]; int n, m ; void Addedge(int a,int b){ edges.push_back((Edge){a,b}); edges.push_back((Edge){b,a}); int m=edges.size(); G[a].push_back(m-2);G[b].push_back(m-1); } int dfs_clock, low[maxn], pre[maxn], q[maxn], fron, scc_cnt, scc[maxn]; int dfs(int u,int fa){ int lowu=pre[u]=++dfs_clock; q[++fron]=u; for(int i=0;i<G[u].size();i++){ int v=edges[G[u][i]].v, lowv; if(u==fa) continue; if(!pre[v]){ lowv=dfs(v,u); lowu=min(lowu,lowv); // if(lowv>=pre[u]){ ok[G[u][i]]=1; ok[G[u][i]^1]=1;} } else{ if(pre[v]<pre[u] && v!=fa) lowu=min(lowu,pre[v]); } } low[u]=lowu; if(pre[u]==low[u]){ scc_cnt++; for(;;){ int x=q[fron--]; scc[x]=scc_cnt; if(x==u) break; } } return lowu; } queue<int> que; int dis[maxn], inq[maxn]; void dist(int x,int f){ dis[x]=dis[f]+1; for(int i=0;i<g[x].size();i++){ int v=g[x][i]; if(v==f) continue;//printf("============ %d\n",v); dist(v,x); } } int main(){ scanf("%d%d",&n,&m); int x,y; for(int i=1;i<=m;i++){ scanf("%d%d",&x,&y); Addedge(x,y); } dfs(1,-1); for(int i=0;i<edges.size();i++){ Edge e=edges[i]; // printf("--------- %d %d\n",scc[e.u],scc[e.v]); if(scc[e.u]!=scc[e.v]) g[scc[e.u]].push_back(scc[e.v]); } dist(1,0);int mx=0,mp=0; for(int i=1;i<=scc_cnt;i++){ if(dis[i]>mx) mx=dis[i],mp=i; } memset(dis,0,sizeof(dis)); dist(mp,0); mx=0; for(int i=1;i<=scc_cnt;i++) mx=max(mx,dis[i]); printf("%d\n",mx-1); return 0; }