Codeforces Round #621 (Div. 1 + Div. 2) 题解
A. Cow and Haybales
思路:
在任何时候,最理想的做法是将最近的一堆草垛从桩1移到左侧。 因此,每天,我们都可以从左到右遍历一堆桩,并将我们看到的第一个草垛移近。 如果某个时候所有干草捆都堆放在第1堆中,我们可以早点停下来
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<stack> #include<iostream> using namespace std; inline ll read(){ ll s=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return s*w; } const int manx=1e5+5; ll a[manx]; int main() { ll kk=read(); while(kk--) { ll n,m; scanf("%lld%lld",&n,&m); for(int i=1;i<=n;i++) cin>>a[i]; ll kkk=0; for(int i=2;i<=n;i++){ if(!a[i]) continue; if(m>=(i-1)){ ll res=m/(i-1); if(a[i]<res) m-=a[i]*(i-1),kkk+=a[i]; else m%=(i-1),kkk+=res; } else break; } cout<<a[1]+kkk<<endl; } return 0; }
B. Cow and Friend
思路:
如果最喜欢的数字里包含x那么答案就为1
否则,设能跳的最远距离为max,如果max大于x的话那么答案就为2,如果小于x的话答案就为(x/max)向上取整
#include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<vector> #define inf 0x3f3f3f3f using namespace std; typedef long long ll; const int maxn=1e5+10; int a[maxn]; int main() { int yy; cin>>yy; while(yy--){ int n,x; scanf("%d%d",&n,&x); int k=0,fla=0; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); if(a[i]<=x){ k=max(a[i],k); } if(a[i]>x){ fla=1; } } if(fla&&k!=x){ cout<<2<<endl; continue; } if(!(x%k)) cout<<x/k<<endl; else cout<<(x/k+1)<<endl; } }
C. Cow and Message
思路:
由于有等差数列这个限制,所以两个以上字母的组合是肯定没有两个字母组合更有,因此我们只要枚举26*26个字母的组合看看哪种组合的出现次数最多即可,注意两个相同数字的组合也有可能是最大的
#include<bits/stdc++.h> #define ll long long using namespace std; #define maxn 100010 ll letter[maxn][30],vis[30][30],hz[30]={0},cnt[30]={0}; int main() { memset(vis,0, sizeof(vis)); memset(letter,0, sizeof(letter)); string s; cin>>s; int n=s.length(); for (int i = 0; i <n ; ++i) { if(i>0){ for (int j = 0; j <26 ; ++j) { letter[i][j]=letter[i-1][j]; } } letter[i][s[i]-'a']++; cnt[s[i]-'a']++; } for (int k = 0; k <n-1 ; ++k) { for (int i = 0; i <26 ; ++i) { hz[i]=letter[n-1][i]-letter[k][i]; vis[s[k]-'a'][i]+=hz[i]; } } ll kk=0; for (int l = 0; l <26 ; ++l) { for (int i = 0; i <26 ; ++i) { if(vis[l][i]>kk) kk=vis[l][i]; } } for (int m = 0; m <26 ; ++m) { if(cnt[m]>kk) kk=cnt[m]; } cout<<kk<<endl; return 0; }
D. Cow and Fields
思路:
由于加上一条边后,只会使最短路继续变短不会边长,所以假设未加边的最短路长度为len
我们先用BFS得到从1的i的最短路p[i] ,从n到i的最短路q[i]
那么加完边之后的最短路就应该为min(len,min(p[s] + q[t] + 1,p[t] + q[s] + 1)
我们继续将p[s] + q[t] < p[t] + q[s]等式变形成为 p[s] - q[s] <p[t] - q[t]
因此我们只需要对p[s] - q[s] 排序,然后遍历一下k个特殊点:那么当前遍历到的t,那么t与之前所有的点直接的最短路都是min(p[s]+q[t]+1,len),把p[s]的最大值记录一下即可。
#include<iostream> #include<algorithm> #include<cstring> #include<queue> #include<vector> #define inf 0x3f3f3f3f using namespace std; const int maxn=2e5+10; int dis[2][maxn],a[maxn],vis[maxn]; int n,m,k; vector<int> e[maxn]; int cmp(int x,int y){return dis[0][x]-dis[1][x]<dis[0][y]-dis[1][y];} void dfs(int *dis,int x) { memset(vis,0,sizeof(vis)); queue<int> q; dis[x]=0; vis[x]=1; q.push(x); while(!q.empty()){ int now=q.front(); q.pop(); for(int i=0;i<e[now].size();i++){ if(!vis[e[now][i]]){ vis[e[now][i]]=1; q.push(e[now][i]); dis[e[now][i]]=dis[now]+1; } } } } int main() { scanf("%d%d%d",&n,&m,&k); for(int i=0;i<k;i++) scanf("%d",&a[i]); for(int i=1;i<=m;i++){ int u,v; scanf("%d%d",&u,&v); e[u].push_back(v); e[v].push_back(u); } dfs(dis[0],1); dfs(dis[1],n); sort(a,a+k,cmp); int ans=0,mx=-inf; for(int i=0;i<k;i++){ ans=max(ans,mx+dis[1][a[i]]+1); mx=max(mx,dis[0][a[i]]); } cout<<min(dis[0][n],ans)<<endl; }