Codeforces Round #407 (Div. 2)
来自FallDream的博客,未经允许,请勿转载,谢谢。
------------------------------------------------------
A.Anastasia and pebbles
你有两个口袋,每种口袋最多只能装k个物品,有n种物品,每种物品有ai个,两种不同的物品不能混在一起,问最少要装多少次.
题解:.............
#include<iostream> #include<cstdio> #include<cmath> #include<queue> #include<cstring> #include<queue> #include<algorithm> #include<map> #define ll long long using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } ll n,k; ll ans=0; int main() { n=read();k=read(); for(int i=1;i<=n;i++) { ll x=read(); ans+=(x+k-1)/k; } cout<<(ans+1)/2; return 0; }
B.Masha and geometric depression
给定一个等比数列,第一项是b1,之后每一项是前一项乘以q,但是b1和q都可以是负数或0。你还有m个不吉利的数字。每当满足abs(b)<=l的时候,你会把b写出来,除非它是一个不吉利的数字。
问你会写出多少个数字,当然你可能写出无限多的数字。
题解:大判断。 一开始我以为不满足还能继续写....结果pretest WA了一排...
#include<iostream> #include<cstdio> #include<cmath> #include<queue> #include<cstring> #include<queue> #include<algorithm> #include<map> #define ll long long using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } int b1,q,l,m; map<int,bool> mp; inline int abs(int x){return x<0?-x:x;} int main() { b1=read();q=read();l=read();m=read(); if(abs(b1)>l) return 0*puts("0"); for(int i=1;i<=m;i++)mp[read()]=1; if(b1==0) { if(mp[0])return 0*puts("0"); else return 0*puts("inf"); } if(q==0) { if(!mp[0])return 0*puts("inf"); if(abs(b1)<=l&&!mp[b1]) return 0*puts("1"); puts("0"); return 0; } if(q==1) { if(abs(b1)<=l&&!mp[b1])return 0*puts("inf"); else return 0*puts("0"); } if(q==-1) { int ans=0; if(abs(b1)<=l&&!mp[b1])ans++; if(abs(b1)<=l&&!mp[-b1]) ans++; if(ans) return 0*puts("inf"); else return 0*puts("0"); } else { int ans=(abs(b1)>l||mp[b1])?0:1; while(1LL*abs(q)*abs(b1)<=(ll)l) { b1*=q; if(abs(b1)<=l&&!mp[b1])ans++; } cout<<ans<<endl; } return 0; }
C.Functions again
给定一个数字序列ai和函数f,求f的最大值。 $n\leqslant 100000$
题解:发现每一种$|a[i]-a[i+1]|$只有两种不同的贡献,分开计算即可。
#include<iostream> #include<cstdio> #include<cmath> #include<queue> #include<cstring> #include<queue> #include<algorithm> #define ll long long #define INF 1000000000 #define MN 100000000 using namespace std; inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } int n; int a[100005]; ll f[100005],f2[100005]; ll ans=0; int abs(int x){return x<0?-x:x;} int main() { n=read(); for(int i=1;i<=n;i++)a[i]=read(); for(int i=1;i<=n;i++) f[i]=f[i-1]+1LL*(i&1?1:-1)*abs(a[i]-a[i+1]); for(int i=1;i<=n;i++) f2[i]=f2[i-1]+1LL*(i&1?-1:1)*abs(a[i]-a[i+1]); ll minn=0; for(int i=1;i<n;i++) { ans=max(ans,f[i]-minn); if(i%2==0)minn=min(minn,f[i]); } minn=f2[1]; for(int i=2;i<n;i++) { // cout<<i<<" "<<f2[i]<<" "<<ans<<" "<<minn<<endl; ans=max(ans,f2[i]-minn); if(i&1)minn=min(minn,f2[i]); } cout<<ans<<endl; return 0; }
D. Weird journey
给定一个无向图,可能有自环,无重边,你要求出满足恰好有两条边只走了一次,其它都走了两次的路径数量。两种方案不同当且仅当边不同。 $n,m\leqslant 10^{6}$
题解:先判联通。然后我们把自环和普通边分开考虑。
如果都选普通边,那么这两条边一定要有公共点,用度数计算一下即可。
如果一个选自环,那么显然任意普通边都能成为另一条边。
如果两个都选自环,那么显然没问题。
#include<iostream> #include<cstdio> #define ll long long #define MN 1000000 using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } int n,m,cnt=0,head[MN+5],num=0,num2=0,s[MN+5]; struct edge{int to,next;}e[MN*2+5]; ll ans=0; bool mark[MN+5],b[MN+5]; void ins (int f,int t){e[++cnt]=(edge){t,head[f]};head[f]=cnt;} void dfs(int x) { mark[x]=1; for(int i=head[x];i;i=e[i].next) if(!mark[e[i].to]) dfs(e[i].to); } int main() { n=read();m=read(); for(int i=1;i<=m;i++) { int u=read(),v=read(); if(u==v) num2++,b[u]=1; else ins(u,v),ins(v,u),num++,s[u]++,s[v]++; } for(int i=1;i<=n;i++) if(b[i]||head[i]) { dfs(i);break; } for(int i=1;i<=n;i++) if(!mark[i]&&(head[i]||b[i])) return 0*puts("0"); for(int i=1;i<=n;i++) ans+=1LL*s[i]*(s[i]-1)/2; ans+=1LL*num2*(m-num2)+1LL*num2*(num2-1)/2; printf("%lld",ans); return 0; }
E. The Great Mixing
给定n个数ai,你要从中选出最少的数,每个数可以选任意次,使得平均值等于k $n\leqslant 10^{6} , ai,k\leqslant 1000$
题解:显然n最多只有1000种,然后我们分成正的和负的考虑。我们发现我们选的数的总和不会超过$10^{6}$,所以直接bfs就可以了,复杂度不是满的,应该能比较快找出答案。
数据挺水的,直接dp好像也能过。
#include<iostream> #include<cstdio> #define MAXN 1000000 using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } int n,k; bool mark[2005]; int s[1005],q[MAXN+5],top=1,cnt=0,d[MAXN+5]; int main() { k=read();n=read(); for(int i=1;i<=n;i++) { int x=read()-k+1000; if(!mark[x]) mark[x]=1,s[++cnt]=x-1000; } d[0]=1; for(int i=1;i<=top;i++) for(int j=1;j<=cnt;j++) { if(s[j]+q[i]==0) return 0*printf("%d",d[q[i]]); if(s[j]+q[i]<=MAXN&&s[j]+q[i]>=0&&!d[s[j]+q[i]]) d[s[j]+q[i]]=d[q[i]]+1,q[++top]=s[j]+q[i]; } puts("-1"); return 0; }