Codeforces Round #441 Div. 2题解
A.直接判断相邻的边是不是最短边 是就来回走 不然就走一条第二的然后再来回走
#include<cstdio> #include<cstring> #include<algorithm> int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int n,a,b,c; int main(){ n=read(); a=read(); b=read(); c=read(); if(n==1) return printf("0\n"),0; if(a<=b&&a<=c) printf("%d\n",a*(n-1)); else if(b<=a&&b<=c) printf("%d\n",b*(n-1)); else printf("%d\n",c*(n-2)+std::min(a,b)); return 0; }
B. 因为(a-b)%k==0 --> a%k==b%k 所以每个数%m然后扫一遍就可以辣
#include<cstdio> #include<cstring> #include<algorithm> const int M=2e5+7; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int n,k,m; int f[M],v[M]; int main(){ n=read(); k=read(); m=read(); for(int i=1;i<=n;i++) v[i]=read(),f[v[i]%m]++; for(int i=0;i<=m;i++)if(f[i]>=k){ int sum=0; printf("Yes\n"); for(int j=1;j<=n;j++)if(v[j]%m==i){ printf("%d ",v[j]); sum++; if(sum==k) break; } return 0; }printf("No\n"); return 0; }
C. 这道题就是求x 满足x+x的每一位的值==n 因为最多九位 9*9==81 所以你往前扫一下100就可以辣
#include<cstdio> #include<cstring> #include<algorithm> const int M=2e5+7; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int n,q[M],cnt; int main(){ n=read(); for(int i=std::max(1,n-100);i<n;i++){ int sum=i,v=i; while(v){sum+=v%10; v/=10;} if(sum==n) q[++cnt]=i; } printf("%d\n",cnt); for(int i=1;i<=cnt;i++) printf("%d\n",q[i]); return 0; }
D. 你开个指针 最后全为x的肯定要剪掉 然后求一下有多少个x在前面就行了
By orzccz, contest: Codeforces Round #441 (Div. 2, by Moscow Team Olympiad), problem: (D) Sorting the Coins, Accepted, # #include<cstdio> #include<cstring> #include<algorithm> const int M=4e5+7; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int n,v[M],cnt,k,ans[M]; int main(){ n=read(); ans[0]=1; for(int i=1;i<=n;i++){ k=read(); v[k]=1; while(v[n-cnt]) cnt++; ans[i]=i-cnt+1; } for(int i=0;i<=n;i++) printf("%d ",ans[i]); return 0; }
E. 这题刚好每个数字是个二元组(改或不改) 然后考虑相邻的两个串 考虑第一个不一样的位置
然后2_sat 跑一下判断是否有解 有解就拓排求一下答案就可以辣
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<queue> using std::min; const int M=4e5+7; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int n,m,k; std::vector<int>c[M]; int first[2*M],cnt; struct node{int from,to,next;}e[2*M],q[2*M]; void ins(int a,int b){e[++cnt]=(node){a,b,first[a]}; first[a]=cnt;} int star[M],sum; void insq(int a,int b){q[++sum]=(node){a,b,star[a]}; star[a]=sum;} bool f; int dfn[M],low[M],st[M],last[M],top,tot; int color[M],h,in[M],op[M],ans[M]; void tarjan(int x){ dfn[x]=low[x]=++tot; st[++top]=x; last[x]=top; for(int i=first[x];i;i=e[i].next){ int now=e[i].to; if(!dfn[now]) tarjan(now),low[x]=min(low[x],low[now]); else if(!color[now]) low[x]=min(low[x],dfn[now]); } if(dfn[x]==low[x]) for(h++;top>=last[x];top--) color[st[top]]=h; } void topsort(){ std::queue<int>qu; for(int i=1;i<=h;i++)if(!in[i]) qu.push(i); while(!qu.empty()){ int x=qu.front(); qu.pop(); if(!ans[x]) ans[x]=1,ans[op[x]]=-1; for(int i=star[x];i;i=q[i].next){ int now=q[i].to; in[now]--; if(!in[now]) qu.push(now); } } } int w[M],wq,x,mark[M]; int main(){ n=read(); m=read(); for(int i=1;i<=n;i++){ k=read(); for(int j=1;j<=k;j++) x=read(),c[i].push_back(x); } for(int i=1;i<n;i++){ bool flag=false; for(int j=0;j<min((int)c[i].size(),(int)c[i+1].size());j++){ if(c[i][j]<c[i+1][j]){ flag=true; ins(c[i][j],c[i+1][j]); ins(c[i+1][j]+m,c[i][j]+m); break; } if(c[i][j]>c[i+1][j]){ flag=true; ins(c[i][j],c[i][j]+m); ins(c[i+1][j]+m,c[i+1][j]); break; } } if(!flag&&c[i].size()>c[i+1].size()) return printf("No\n"),0; } for(int i=1;i<=2*m;i++) if(!dfn[i]) tarjan(i); for(int i=1;i<=m;i++) if(color[i]==color[i+m]) return printf("No\n"),0; else op[color[i]]=color[i+m],op[color[i+m]]=color[i]; for(int i=1;i<=cnt;i++)if(color[e[i].from]!=color[e[i].to]) insq(color[e[i].to],color[e[i].from]),in[color[e[i].from]]++; topsort(); for(int i=1;i<=m;i++) if(ans[color[i+m]]==1) w[++wq]=i; printf("Yes\n%d\n",wq); for(int i=1;i<=wq;i++) printf("%d ",w[i]); return 0; }
F. F这题比赛没时间写QAQ 这题是要求有多少个区间 区间或(|) 值大于区间max
这题我们可以先用单调栈找一下每个数统御的区间(也就是这些区间内这个数为max)
然后再找他能往左往右延伸而不改变值 然后一波计算(算容斥吧)将总的方案数减去不合法的
就是合法的方案了 至于怎么处理每个数能往左右延伸多远 我们可以考虑每一位
如果一个数和另一个数或完变大 那么就一定是另一个数有这个数没有的1的位置
这样的预处理是nlogn 的然后就可以做辣
#include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> #include<algorithm> #define LL long long using namespace std; const int M=500007,inf=2e9; int n,top; int stk[M],v[M],d[M][32],pre[M][32],L[M],next[M][32],R[M],cnt[M]; LL ans; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int main(){ n=read(); for(int i=1;i<=n;i++){ v[i]=read(); for(int x=v[i];x;x>>=1) d[i][++cnt[i]]=x&1; } for(int j=1,last=0;j<=30;j++,last=0) for(int i=1;i<=n;i++){ if(!d[i][j]) pre[i][j]=last; if(d[i][j]) last=i; } for(int i=1;i<=n;i++) for(int j=1;j<=30;j++) if(!d[i][j]) L[i]=max(L[i],pre[i][j]); memset(next,32,sizeof(next)); for(int j=1,last=n+1;j<=30;j++,last=n+1) for(int i=n;i;i--){ if(!d[i][j]) next[i][j]=last; if(d[i][j]) last=i; } memset(R,32,sizeof(R)); for(int i=1;i<=n;i++) for(int j=1;j<=30;j++) if(!d[i][j]) R[i]=min(R[i],next[i][j]); v[++n]=inf; for(int i=1;i<=n;i++){ for(;top&&v[i]>=v[stk[top]];top--){ ans+=1ll*((i-1)-stk[top]+1)*(stk[top]-(stk[top-1]+1)+1); ans-=1ll*(1ll*stk[top]-1ll*max(stk[top-1]+1,L[stk[top]]+1)+1)*(min(i-1,R[stk[top]]-1)-stk[top]+1); } stk[++top]=i; } printf("%I64d\n",ans); }