Educational Codeforces Round 92 (Rated for Div. 2)
A
签到
B
直接DP,f[i][j]表示前i步j步向左的最大值,位置可以直接计算
#include<bits/stdc++.h> using namespace std; const int N=1e5+7; int n,k,z,ans,a[N],f[N][6]; int main() { int T;scanf("%d",&T); while(T--) { scanf("%d%d%d",&n,&k,&z); for(int i=1;i<=n;i++)for(int j=0;j<=z;j++)f[i][j]=0; for(int i=1;i<=n;i++)scanf("%d",&a[i]); f[0][0]=a[1]; for(int i=1;i<=k;i++) for(int j=0;j<=min(i-1,z);j++) { int pos=i-2*j; if(pos>1&&j<z)f[i][j+1]=max(f[i][j+1],f[i-1][j]+a[pos-1]); if(pos<n)f[i][j]=max(f[i][j],f[i-1][j]+a[pos+1]); } ans=0; for(int i=0;i<=z;i++)ans=max(ans,f[k][i]); printf("%d\n",ans); } }
C
求最少删除次数等价于求最长序列。容易发现,最长序列有两种情况:1、全为字符a;2、长度为偶数,ababab交替。方案1记录数量最多的数字,方案2枚举ab扫描一遍即可,复杂度O(81Σn)
#include<bits/stdc++.h> using namespace std; int n,ans; char s[200050]; int main() { int T;scanf("%d",&T); while(T--) { scanf("%s",s+1); n=strlen(s+1); int num; ans=0; for(int i='0';i<='9';i++) { num=0; for(int j=1;j<=n;j++)if(s[j]==i)num++; ans=max(ans,num); } for(int a='0';a<='9';a++) for(int b='0';b<='9';b++) if(a!=b) { int now=a,num=0; for(int i=1;i<=n;i++)if(s[i]==now) { num++; now=now==a?b:a; } if(num%2)num--; ans=max(ans,num); } printf("%d\n",n-ans); } }
D
对于两条线段,不妨三种情况:1、完全包含;2、部分包含;3、无交集。前两种直接计算,尽量改变重叠部分。第三种可以枚举改变i组线段,然后转化为第二种方案。时间复杂度O(Tn)(不然T,n给你那么小干嘛?)
#include<bits/stdc++.h> using namespace std; typedef long long ll; int T; ll n,k,l1,r1,l2,r2,ans; int main() { cin>>T; while(T--) { cin>>n>>k>>l1>>r1>>l2>>r2; if(l1>l2||l1==l2&&r1<r2)swap(l1,l2),swap(r1,r2); if(r1>=r2) { ll rst=(r1-l1)-(r2-l2); if(k<=(r2-l2)*n)puts("0"); else if(k<=(r1-l1)*n)printf("%lld\n",k-(r2-l2)*n); else printf("%lld\n",rst*n+(k-(r1-l1)*n)*2); } else if(r1>=l2) { ll rst=(r2-l1)-(r1-l2); if(k<=(r1-l2)*n)puts("0"); else if(k<=(r2-l1)*n)printf("%lld\n",k-(r1-l2)*n); else printf("%lld\n",rst*n+(k-(r2-l1)*n)*2); } else{ ans=9e18; for(int i=1;i<=n;i++) { ll sum=i*(l2-r1); if(k<=(r2-l1)*i)sum+=k; else sum+=(r2-l1)*i+(k-(r2-l1)*i)*2; ans=min(ans,sum); } printf("%lld\n",ans); } } }
E
老年选手不会用脑子了!若a月b日和b月a日如果是一周的同一天,则(b-1)*d+a-( (a-1)*d+b)被w整除,化简得(b-a)(d-1)%w==0,设c=b-a,则c*(d-1)%w==0。若(d-1)%w=0,则c为任意正整数 ,ans=md*(md-1)/2,md=min(m,d)。若(d-1)%w!=0,那c是lcm(w,(d-1)%w)/(d-1)%w的整数倍
#include<bits/stdc++.h> using namespace std; int main() { int T;scanf("%d",&T); while(T--) { int m,d,w,g;scanf("%d%d%d",&m,&d,&w); g=__gcd(w,d-1),w/=g,m=min(m,d); long long y=m/w; printf("%lld\n",y*m-y*(y+1)/2*w); } }
F
蒟蒻早知道看这题了,这题没有啥思维难度。根据颜色不同用2棵线段树维护DP即可。
#include<bits/stdc++.h> #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define rot 0,tot,1 using namespace std; const int N=4e5+7; struct ST{ int mx[N<<2],lazy[N<<2]; void addtag(int rt,int v){} void pushdown(int rt) {if(lazy[rt])mx[rt<<1]+=lazy[rt],lazy[rt<<1]+=lazy[rt],mx[rt<<1|1]+=lazy[rt],lazy[rt<<1|1]+=lazy[rt],lazy[rt]=0;} void update(int k,int v,int l,int r,int rt) { if(l==r){mx[rt]=max(mx[rt],v);return;} pushdown(rt); int m=l+r>>1; if(k<=m)update(k,v,lson);else update(k,v,rson); mx[rt]=max(mx[rt<<1],mx[rt<<1|1]); } void add(int L,int R,int v,int l,int r,int rt) { if(L<=l&&r<=R){mx[rt]+=v,lazy[rt]+=v;return;} pushdown(rt); int m=l+r>>1; if(L<=m)add(L,R,v,lson); if(R>m)add(L,R,v,rson); mx[rt]=max(mx[rt<<1],mx[rt<<1|1]); } int query(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R)return mx[rt]; pushdown(rt); int m=l+r>>1,ret=0; if(L<=m)ret=max(ret,query(L,R,lson)); if(R>m)ret=max(ret,query(L,R,rson)); return ret; } }tr[2]; struct node{int l,r,t;}a[N]; int n,tot,b[N]; bool cmp(node a,node b){return a.l<b.l;} int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].t),a[i].t--,b[++tot]=a[i].l,b[++tot]=a[i].r; sort(b+1,b+tot+1); tot=unique(b+1,b+tot+1)-b-1; for(int i=1;i<=n;i++) a[i].l=lower_bound(b+1,b+tot+1,a[i].l)-b,a[i].r=lower_bound(b+1,b+tot+1,a[i].r)-b; sort(a+1,a+n+1,cmp); for(int i=1;i<=n;i++) { tr[a[i].t].update(a[i].r,max(tr[a[i].t^1].query(0,a[i].l-1,rot),tr[a[i].t].query(0,a[i].r,rot))+1,rot); if(a[i].r<tot)tr[a[i].t].add(a[i].r+1,tot,1,rot); } printf("%d",max(tr[0].query(0,tot,rot),tr[1].query(0,tot,rot))); }
G
综合性很强的一题。先点双缩点,变成一个个强连通分量,然后以关键点为根,将树视为有根树,进行树上换根DP即可。
#include<bits/stdc++.h> #define pb push_back using namespace std; typedef long long ll; const int N=3e5+7; struct edge{int u,v,w;}e[N]; int n,m,cnt,rt,tot,tp,fa[N],low[N],dfn[N],st[N],bel[N],c[N],sz[N]; bool sp[N],is[N]; ll a[N],b[N],f[N],ans[N]; vector<pair<int,int> > T[N]; vector<int>G[N]; void tarjan(int u,int f) { low[u]=dfn[u]=++tot,st[++tp]=u; for(int v:G[u]) if(v!=f) { if(!dfn[v])tarjan(v,u),low[u]=min(low[u], low[v]); else low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]) { ++cnt;int v=0; while(u!=v)a[bel[v=st[tp--]]=cnt]+=c[v],is[cnt]|=sp[v]; } } int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);} void dfs1(int u, int f) { sz[u]=is[u],b[u]=a[u]; for(auto e:T[u]) if(e.first!=f) { dfs1(e.first,u),sz[u]+=sz[e.first]; if(!sz[e.first])fa[e.first]=u,b[u]+=b[e.first]; } } void dfs2(int u,int fa) { f[u]=b[u]; for(auto e:T[u]) if(e.first!=fa&&sz[e.first]) { dfs2(e.first, u); if(f[e.first]>e.second)f[u]+=f[e.first]-e.second; } } void dfs3(int u,int fa) { ans[u]=f[u]; for(auto e:T[u]) if(e.first!=fa&&sz[e.first]) { f[u]-=max(0ll,f[e.first]-e.second); f[e.first]+=max(0ll,f[u]-e.second); dfs3(e.first,u); f[e.first]-=max(0ll,f[u]-e.second); f[u]+=max(0ll,f[e.first]-e.second); } } int main() { int k,x;scanf("%d%d%d",&n,&m,&k); while(k--)scanf("%d",&x),sp[x]=1; for(int i=1;i<=n;++i)scanf("%d",&c[i]); for(int i=1;i<=m;++i)scanf("%d",&e[i].w); for(int i=1;i<=m;++i) scanf("%d%d",&e[i].u,&e[i].v),G[e[i].u].pb(e[i].v),G[e[i].v].pb(e[i].u); tarjan(1,0); for(int i=1;i<=m;++i) { int u=bel[e[i].u],v=bel[e[i].v]; if(u!=v)T[u].pb(make_pair(v,e[i].w)),T[v].pb(make_pair(u,e[i].w)); } rt=0; for(int i=1;i<=cnt;++i)if(is[i])rt=i; for(int i=1;i<=cnt;++i)fa[i]=i; dfs1(rt,0),dfs2(rt,0),dfs3(rt,0); for(int i=1;i<=n;++i)printf("%lld ",ans[find(bel[i])]); }
rank=216 rating+=222
新号卡线上紫啦!