Codeforces Round #621 (Div. 1 + Div. 2)【A、B、C、D】(题解)(持续更新)

涵盖知识点:DP、图论etc.

比赛链接:

https://codeforces.com/contest/1307

A:Cow and Haybales

题意:每一步可以将第n个数字-1,第n-1个数字+1.给你d步问你第1个数字最大能变为多少。

题解:贪心、模拟。一个一个扫描判断步数是否足够。

AC代码:

 1 //A
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 int num[110];
 5 int main(){
 6     int t;
 7     cin>>t;
 8     while(t--){
 9         int n,d;
10         cin>>n>>d;
11         for(int i=0;i<n;i++){
12             cin>>num[i];
13         }
14         int res=num[0];
15         for(int i=1;i<n;i++){
16             if(num[i]*i<=d){
17                 res+=num[i];
18                 d-=num[i]*i;
19             }else{
20                 res+=d/i;
21                 break;
22             }
23         }
24         cout<<res<<"\n";
25     }
26     return 0;
27 }

B:Cow and Friend

题意:在2D平面内要求从(0,0)跳到(x,0)。每次跳的距离需要满足给定的n个具体数值。问最少条几次可以满足条件。

题解:如果x在所给定的n个数值中,那么只需要一步。否则,设n个数值内最大值为m,最终所求的答案ans=max(2,ceil(x/m)).证明:1.至少两步。2.前ans-2步沿着x轴跳动m(ans-2)的距离,第ans-1步总存在一个方向使得最后一步的起点和终点之间的距离在n个数之内。

AC代码:

 1 //B
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 set<int> s;
 5 
 6 int main(){
 7     int t;
 8     cin>>t;
 9     while(t--){
10         s.clear();
11         int n,x;
12         cin>>n>>x;
13         int ma=0;
14         while(n--){
15             int a;
16             cin>>a;
17             s.insert(a);
18             ma=max(a,ma);
19         }
20         if(s.count(x)){
21             cout<<"1\n";
22         }else{
23             cout<<max(2,(x+ma-1)/ma)<<"\n";
24         }
25     }
26     return 0;
27 }

C:Cow and Message

题意:在一个字符串中下标满足等差数列的子序列当中找出出现次数最多的那个子序列。

题解:如果子序列长度大于2,那么一个长度为2或者长度为1的子序列必定同时满足条件。所以只考虑长度为1的和长度为2的子序列。长度为1的扫描一遍,长度为2的dp一下即可。

AC代码:

 1 //C
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 const int maxn=26;
 5 typedef long long ll;
 6 ll cnt[maxn],dp[maxn][maxn];
 7 int main(){
 8     string s;
 9     cin>>s;
10     for(int i=0;i<s.length();i++){
11         for(int j=0;j<maxn;j++){
12             dp[j][s[i]-'a']+=cnt[j];
13         }
14         cnt[s[i]-'a']++;
15     }
16     ll res=0;
17     for(int i=0;i<maxn;i++){
18         res=max(res,cnt[i]);
19         for(int j=0;j<maxn;j++){
20             res=max(res,dp[i][j]);
21         }
22     }
23     cout<<res<<"\n";
24     return 0;
25 }

D:Cow and Fields

题意:有k个特殊点,必须在其中两个之间加一条路径,问选哪两个可以是从1到n的最短距离最长。

题解:设选的两个点为a、b。先搜每个点距离1和n的距离。设dis(1,a)+dis(b,n)<dis(1,b)+dis(a,n),所以遍历k个排序后的特殊点一次即可得出答案。(通过dis(1,a)-dis(a,n)的从小到大的顺序排序即可)

 1 //D
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 const int maxn=2e5+10,inf=0x3f3f3f3f;
 5 typedef pair<int,int> pii;
 6 int sp[maxn],dis[2][maxn];
 7 vector<int> edg[maxn];
 8 void bfs(int st,int idx){
 9     dis[idx][st]=0;
10     queue<int> q;
11     q.push(st);
12     while(!q.empty()){
13         int u=q.front();
14         q.pop();
15         for(auto v:edg[u]){
16             if(dis[idx][v]==inf){
17                 dis[idx][v]=dis[idx][u]+1;
18                 q.push(v);
19             }
20         }
21     }
22 }
23 
24 int main(){
25     memset(dis,inf,sizeof dis);
26     int n,m,k;
27     cin>>n>>m>>k;
28     for(int i=1;i<=k;i++){
29         scanf("%d",&sp[i]);
30     }
31     sort(sp+1,sp+1+k);
32     for(int i=1;i<=m;i++){
33         int u,v;
34         scanf("%d%d",&u,&v);
35         edg[u].push_back(v);
36         edg[v].push_back(u);
37     }
38     bfs(1,0);
39     bfs(n,1);
40     vector<pii> v;
41     for(int i=1;i<=k;i++){
42         v.emplace_back(dis[0][sp[i]]-dis[1][sp[i]],sp[i]);
43     }
44     sort(v.begin(),v.end());
45     int res1=0,res2=-inf;
46     for(auto i:v){
47         res1=max(res1,res2+dis[1][i.second]);
48         res2=max(res2,dis[0][i.second]);
49     }
50     cout<<min(dis[0][n],res1+1)<<"\n";
51     return 0;
52 }

E:Cow and Treats

F:Cow and Vacation

G:Cow and Exercise

猜你喜欢

转载自www.cnblogs.com/charles1999/p/12327855.html