Educational Codeforces Round 81 (Rated for Div. 2) A-E简要题解

链接:https://codeforces.com/contest/1295

A. Display The Number

贪心思路,尽可能放置更多位,如果n为奇数,消耗3去放置一个7,剩下的放1

AC代码:

 1 #include<bits/stdc++.h>
 2 #define inf 0x3f3f3f3f
 3 using namespace std;
 4 int n,m;
 5 int main(){
 6     int t;
 7     cin>>t;
 8     while(t--){
 9         int n;
10         cin>>n;
11         string ans = "";
12         if(n%2 == 1) ans.append(1,'7'),ans.append((n-3)/2,'1'); 
13         else ans.append(n/2,'1');
14         cout<<ans<<endl; 
15     }
16     return 0;
17 }

B. Infinite Prefixes

前缀和思路,存字符串前n个位置的前缀和,如果cnt0+cnt1 = 0,且 x 在前缀和中出现过,那么就是无限的。

其他情况扫一遍字符串的前缀和,然后与x的差值和f[n]取余,如果为0,说明差值可以用任意个字符串的cnt0-cnt1拼接起来,ans就++

 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,x;
 9         cin>>n>>x;
10         string s;
11         cin>>s;
12         int f[n+1];
13         f[0] = 0;
14         int can = 0;
15         for(int i = 0;i<n;i++){
16             if(f[i] == x) can = 1;
17             if(s[i] == '1') f[i+1] = f[i]-1;
18             else f[i+1] = f[i] + 1;
19         } 
20         if(f[n] == x) can = 1;
21         if(can == 1 && f[n] == 0) {
22             cout<<-1<<endl;
23             continue;
24         }
25         int ans = 0;
26         ll d = f[n];
27     //    cout<<d<<endl;
28         for(int i = 0;i<=n;i++){
29             if(f[i] == x) ans++;
30             if(i!=0 && f[i]<x && d>0 &&(x-f[i])%d==0) ans++;
31             if(i!=0 && f[i]>x && d<0 &&(f[i]-x)%(-d)==0) ans++;
32         }
33         cout<<ans<<endl; 
34     }
35     return 0;
36 }

C. Obtain The String

贪心思路,用一个next二维数组存储当前位置i 下一个26个字母的距离最近的位置,然后按需求跳转过去,如果找不到,那么需要的字串数量就+1,再从头开始扫描原串。

 1 #include<bits/stdc++.h>
 2 typedef long long ll;
 3 using namespace std;
 4 const int maxn = 1e5+5;
 5 int main()
 6 {
 7     int n;
 8     cin>>n;
 9     while(n--){
10         string s,t;
11         cin>>s>>t;
12         int next[s.length()+1][26];
13         for(int i = 0;i<26;i++) next[s.length()][i] = -1;
14         for(int i = s.length()-1;i>=0;i--){
15             for(int j = 0;j<26;j++) next[i][j] = next[i+1][j];//存储i后面,26个字母距离i最近的位置
16             int cur = s[i]-'a';
17             next[i][cur] = i+1;
18         }
19         int ans = 1;
20         int cur = 0;
21         bool f = true;
22         for(int i = 0;i<t.length();i++){
23             int now = t[i]-'a';
24             if(next[cur][now]!=-1) cur = next[cur][now];//跳转过去
25             else{
26                 ans++;//如果找不的ans就++
27                 cur = 0;
28                 if(next[cur][now] == -1){//如果还没有,说明无法拼接起来
29                     f = false;
30                     break;
31                 }
32                 cur = next[cur][now];
33             }
34         }
35         if(!f) cout<<-1<<endl;
36         else cout<<ans<<endl;
37     }
38     return 0;
39 }

D. Same GCDs

设gcd(a,m)= n,那么找gcd(a +x ,m)= n个数,其实就等于找gcd((a+x)/n,m/n) = 1的个数,等价于求m/n的欧拉函数

 1 #include<bits/stdc++.h>
 2 typedef long long ll;
 3 using namespace std;
 4 ll euler_phi(ll n) {
 5   ll m = ll(sqrt(n + 0.5));
 6   ll ans = n;
 7   for (ll i = 2; i <= m; i++)
 8     if (n % i == 0) {
 9       ans = ans / i * (i - 1);
10       while (n % i == 0) n /= i;
11     }
12   if (n > 1) ans = ans / n * (n - 1);
13   return ans;
14 }
15 ll gcd(ll a, ll b) {
16   if (b == 0) return a;
17   return gcd(b, a % b);
18 }
19 int main()
20 {
21     int t;
22     cin>>t;
23     while(t--){
24         ll a,m;
25         cin>>a>>m;
26         m=m/gcd(a,m);
27         ll x = euler_phi(m);
28         cout<<x<<endl;
29     } 
30     return 0;
31 }

E. Permutation Separation

建一颗线段树,叶子结点是花费从1到i所需要花费的前缀和,表示前i个元素全部移动到右边的花费,再维护区间最小值,然后从1到n-1扫一遍,对于第i个位置,找到数字i在序列中的位置 pos ,将区间1到pos-1加上数字i移动的花费,pos到n-1减去数字i移动的花费,因为位置大于等于i 的时候,不需要将数字i移动到右边,位置小于i 时,需要把数字i移动到左边,所以需要增加数字i的花费,结合线段树维护的是前缀和数组,那么对于每一个位置i 用线段树维护的最小值去更新答案ans即可。

 1 #include<bits/stdc++.h>
 2 typedef long long ll;
 3 using namespace std;
 4 const int maxn = 2e5+5;
 5 ll pos[maxn],cost[maxn],a[maxn],sum[maxn];
 6 struct segT{
 7     ll l,r;
 8     ll dat,lz;
 9 }t[maxn*4];
10 void build(ll p,ll l,ll r){
11     t[p].l = l,t[p].r = r;
12     if(l == r) { t[p].dat = sum[l] ,t[p].lz = 0;return;}
13     ll mid = (l+r)/2;
14     build(p*2,l,mid);
15     build(p*2+1,mid+1,r);
16     t[p].dat = min(t[p*2].dat ,t[p*2+1].dat );
17 }
18 void upd(ll p,ll L,ll R,ll v){
19     if(t[p].l >= L&&t[p].r <= R ) {t[p].dat += v,t[p].lz +=v;return;}
20     if (t[p].lz && L!=R ) {
21     t[p * 2].dat += t[p].lz ,t[p*2+1].dat +=t[p].lz  ;
22     t[p * 2].lz  += t[p].lz ,t[p*2+1].lz += t[p].lz;  
23     t[p].lz = 0;                             
24     }
25     int mid = (t[p].l + t[p].r )/2;
26     if(L<=mid) upd(p*2,L,R,v);
27     if(R>mid) upd(p*2+1,L,R,v);
28     t[p].dat = min(t[p*2].dat ,t[p*2+1].dat );
29 }
30 int query(ll p,ll l,ll r){
31     if(l<=t[p].l && r>=t[p].r ) return t[p].dat ;
32     int mid = (t[p].l + t[p].r )/2;
33     int val = 0x3f3f3f3f;
34     if(l<=mid) val = min(val,query(p*2,l,r));
35     if(r>mid)  val = min(val,query(p*2+1,l,r));
36     return val;
37 }
38 int main()
39 {
40     int n;
41     scanf("%d",&n);
42     for(int i = 1;i<=n;i++) {
43         scanf("%lld",&a[i]);
44         pos[a[i]] = i;
45     }
46     for(int i = 1;i<=n;i++){
47         scanf("%lld",&cost[i]);
48         sum[i] = sum[i-1] + cost[i];
49     }
50     build(1,1,n-1);
51     ll ans = cost[n];
52     ans = min(ans,t[1].dat );//特判
53     for(int i = 1;i<=n;i++){
54         if(pos[i]!=n) upd(1,pos[i],n-1,-cost[pos[i]]);
55         if(pos[i]!=1) upd(1,1,pos[i]-1,cost[pos[i]]);
56         ans = min(ans,t[1].dat);
57     }
58     printf("%lld",ans);
59     return 0;
60 }
原文地址:https://www.cnblogs.com/AaronChang/p/12253371.html