Educational Codeforces Round 84 (Rated for Div. 2) A-E题解

A. Sum of Odd Integers

首先可以算出从1开始到第k个奇数之和。如果和大于n,则不可能存在k个奇数加和等于n,否则用n减去前k个奇数的和,这个差值若是偶数,直接加到最大的奇数上,就可以满足题意要求,否则输出no。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 int main(){
 5     int t;
 6     cin>>t;
 7     while(t--){
 8         ll n,k;
 9         cin>>n>>k;
10         ll d = (1+2*k-1)*k/2;
11         ll t = n - d;
12         if(t>=0 && t%2 == 0) cout<<"YES"<<endl;
13         else cout<<"NO"<<endl;
14     }
15     return 0;
16 }
View Code

 

B. Princesses and Princes

贪心的去匹配每个Princesses当前可以匹配的最中意的Princes,如果存在没有匹配上的Princesses,随便和一个没有匹配过的Princes匹配即可。纯阅读理解题。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 int main(){
 5     int t;
 6     cin>>t;
 7     while(t--){
 8         int n;cin>>n;
 9         vector<int> v[n];
10         int pr[n+1];
11         int dr[n+1];
12         memset(dr,0,sizeof(dr));
13         memset(pr,0,sizeof(pr));
14         for(int i = 1;i<=n;i++){
15             int k;scanf("%d",&k);
16             for(int j = 0;j<k;j++){
17                 int t;scanf("%d",&t);
18                 if(dr[i] == 0 && pr[t] == 0) pr[t] = 1,dr[i] = 1;
19             }
20         }
21         vector<int> r1,r2;
22         int f = 0;
23         for(int i = 1;i<=n;i++){
24             if(dr[i] == 0) {
25                 f = 1;r1.push_back(i);
26             }
27             if(pr[i] == 0) {
28                 f = 1;r2.push_back(i);
29             }
30         }
31         if(f == 0){
32             cout<<"OPTIMAL"<<endl;
33         }
34         else{
35             cout<<"IMPROVE"<<endl;
36             for(int i = 0;i<r1.size();i++){
37                 cout<<r1[i]<<" "<<r2[i]<<endl; 
38                 break;
39             }
40         }
41     }
42     return 0;
43 }
View Code

 

C. Game with Chips

构造题。按最坏的情况考虑,直接先把所有的chips移动到一个角落里,然后从这个角落S形遍历一遍棋盘即可,这样必定可以经过棋盘上所有的关键点,整个操作必定不会超过2*m*n次,故不可能存在-1的情况。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 int main()
 5 {
 6  
 7     int n,m,k;
 8     cin>>n>>m>>k;
 9     for(int i=1;i<=k;i++)
10     {
11         int x,y;scanf("%d%d",&x,&y);
12     }
13     for(int i=1;i<=k;i++)
14     {
15        int x,y;scanf("%d%d",&x,&y);
16     }
17     int tn=0;
18         tn =tn+n-1+m-1+(n-1)*m+m-1;
19     cout << tn << endl;
20     for(int i=1; i<m; i++ )
21         cout<<"L";
22     for(int i=1; i<n; i++)
23         cout<<"U";
24             for(int i=1; i<n; i++)
25                 {
26                     for(int j=1; j<m; j++)
27                     if(i&1)
28                         cout<<"R";
29                     else
30                         cout<<"L";
31                             printf("D");
32                 }
33     for(int j=1; j<m; j++)
34         if (n&1)
35             printf("R");
36         else
37             printf("L");
38 
39     return 0;
40 }
View Code

 

D. Infinite Path

一道定义在环上的排列幂定义题。p * p = p[ p [ i ] ] ,按照题目所给的定理可以轻易推导出从任意一p[i]出发,做排列幂运算之后最终回到p[i],把i和p[i]连边,这样可以构成一个环,而整个序列可以构成多个不相交环。对于一个环,从任意一点出发,走k步,也就是pk[i] ,会有c[i] = c[pk[i] ] ,也可能会有c[p2k[i] ]......,也就是说每次走从一点开始,相隔k个点,他们的c[i]是相等的,怎么求最小的k?当是从环长度的因子开始枚举,只有是因子k才能从某一起点开始,每次走k步,绕一圈回到这个起点。

预处理所有的环,然后枚举环,在环中枚举环长度的因子,再去检查环上是否存在合法的k,每次取k的最小值。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 2e5 +5;
 5 int k,n,cnt,ans;
 6 int p[maxn],c[maxn],vis[maxn],g[maxn];
 7 bool ok(int x,int y){
 8     for(int i = 1;i<=x;i++){//在长度为x的范围内枚举起点
 9         int f = 0,t = i;
10         for(int j = 1;j<=y;j++){//整个环上有y个相隔x的点
11             if(c[g[t]] != c[g[i]]){//检查每次移动k步到的点,其c值是否相等。
12                 f = 1;break;
13             }
14             t = (t + x - 1) %cnt + 1;//t是下一个点的位置
15         }
16         if(!f) return 1;
17     }
18     return 0;
19 }
20 void dfs(int x){
21     cnt = 1;
22     g[cnt] = x,vis[x] = 1;
23     for(int i = p[x];i!=x;i=p[i]) vis[i] = 1,g[++cnt] = i;//从一点开始预处理环,结点存入g数组
24     for(int i = 1;i<=sqrt(cnt);i++){//枚举环长度cnt的因子
25         if(cnt%i == 0){
26             if(ok(i,cnt/i)) {ans = min(ans,i);return;} //检查k = i是否合法
27             if(ok(cnt/i,i) )ans = min(ans,cnt/i);//检查k = cnt/i是否合法
28         }
29     }
30 }
31 int main()
32 {
33     int t;
34     scanf("%d",&t);
35     while(t--){
36        scanf("%d",&n);
37        for(int i = 1;i<=n;i++) scanf("%d",&p[i]);
38        for(int i = 1;i<=n;i++) scanf("%d",&c[i]);
39        ans = 2e5+10;
40        for(int i = 1;i<=n;i++) vis[i] = 0; 
41        for(int i = 1;i<=n;i++) {
42               if(!vis[i]) dfs(i);
43        }
44        cout<<ans<<endl;
45     }
46     return 0;
47 }
View Code

 

E. Count The Blocks

计数题。n位数,首先考虑block的长度为1,各个位置都可以放置0~10这样不同的数字,一共10个数字,对于其中1个位置,这个位置可以放10种可能的数字,其左右相邻的位放置9种可能的数,不相邻的其他位可以任意放置10个数字。

考虑长度n的数,block长度为k

1.左右两个端点对答案的贡献是2*10*9*10n-k-1 ,2是2个端点,10是端点可以放置10种可能的数,9是其相邻位置只能放9种可能,10n-k-1是其他点可以放置的数字有多少种。

2.中间的长度为k的段,10*9*9*10n-k-2,10是这一段放置10种可能的数字,2个9是这一段左右端点相邻的点要和段内数字不同,有9种可能,10n-k-2 是其他点可以放置的数字有多少种可能,这样的段一共有n-k-1个,再乘一下即可。

首先要预处理一下10的n次方。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const ll mod = 998244353;
 5 const int maxn = 2e5+5;
 6 ll n;
 7 ll f[maxn];
 8 void pre(){
 9     f[1] = 10;
10     for(int i = 2;i<=n;i++){
11        f[i] = f[i-1]*10%mod;        
12     }
13 }
14 int main()
15 {
16     cin>>n;
17     pre();
18     for(int i = 1;i<n;i++){
19         ll d = n + 1 - i;
20         ll x = ((ll(2*9)*f[n-i])%mod + (ll(d-2)*9*9*f[n-i-1])%mod)%mod;
21         cout<<x<<" ";
22     }
23     cout<<10;
24     return 0;
25 }
View Code

 

posted @ 2020-03-26 00:48  AaronChang  阅读(236)  评论(0编辑  收藏  举报