CF Educational Round 81 A-D 题解

A. Display the number

https://codeforces.com/contest/1295/problem/A

题目大意:

显示0-9这十个数字分别需要6,2,5,5,4,5,6,3,7,6个亮块。

现在你有n个亮块,需要你输出你用这n个亮块能组成的最大数字。

显然我们需要保证数字的位数最多,这样数也就越大。

那么如果n是偶数,那就输出n/2个1

否则输出一个7,再输出(n-3)/2个1

#include<bits/stdc++.h>
using namespace std;
 
int main() {
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        if(n%2==0){
            for(int i=0;i<n/2;i++)    cout<<'1';
            cout<<endl;
            continue;
        }
        if(n==3){
            cout<<'7'<<endl;
            continue;
        }
        if(n%2!=0&&n!=3){
            cout<<'7';
            for(int i=0;i<n/2-1;i++) cout<<'1';
            cout<<endl;
            continue;
        }
    }
    return 0;
}

 

B. Infinite Prefixes

https://codeforces.com/contest/1295/problem/B

题目大意:

给你一个01串s和两个整数n,t

n是串s的长度,t是期望的number of(0) - number of(1). (题目中称为balance)

现在你可以不断的重复s得到新的字符串z,求能满足0的个数减去1的个数等于t的字符串z长度的个数,如果有无限个,那就输出-1.

 

有点绕,给个例子解释下

样例:6 10 010010

把s不断重复,比如当z=010010 010010 010010 010010 0100 的时候,t=10,满足题意,这个时候length=28.

同理,length=30,32的时候也满足题意,所以答案输出3.

 

思路的话,可以记录在一个循环内每个位置的balance。

然后计算一下整个串的balance,这里记做cyc

显然这个串是通过自我拼接形成的,所以在新串的每个点,它的balance一定和初始串相应位置的balance对于cyc同余。

那就直接判断(balance-t)/cyc是不是非负整数就可以了,是的话ans+1,否则continue。

当cyc=0而且初始计算出的balance = t的位置存在的话,输出-1.

#include<bits/stdc++.h>
using namespace std;
int s[100005];
 
int main() {
    int t;
    cin>>t;
    while(t--) {
        int n,x;
        cin>>n>>x;
        int s0=0,s1=0;
        for(int i=0; i<n; i++) {
            char r;
            cin>>r;
            if(r=='0')    s0++;
            else s1++;
            s[i]=s0-s1;
        }
        int ans=0;
        if(x==0)    ans++;
        int cyc=s0-s1;
        //cout<<cyc<<endl;
        if(cyc!=0) {
            for(int i=0; i<n; i++) {
                if((x-s[i])/cyc>=0&&(x-s[i])%cyc==0) ans++; //注意一定是非负整数,如果没判等于0的话就把初始=t的情况漏了,最后会fst。(别问我怎么知道的)
            }
            cout<<ans<<endl;
        }
        bool flag=true;
        if(cyc==0) {
            for(int i=0; i<n; i++) {
                if(s[i]==x)    {
                    cout<<"-1"<<endl;
                    flag=false;
                    break;
                }
            }
 
            if(flag==true) {
                cout<<"0"<<endl;
                continue;
            }
            continue;
        }
    }
    return 0;
}

 

 

C.Obtain The String

https://codeforces.com/contest/1295/problem/C

题目大意:给你两个串s,t和一个空串z,每次对z append一个s的子串,问至少要多少次操作才能让z变成t,如果不行就输出-1.

s和t的长度规模1e5

 

这个题有两个做法

先介绍官方的O(n)做法

预处理一个next[i][j]数组,表示在s串中离i位置之后最近的j字符的位置 从后往前dp处理

具体看代码吧 有注释

//悬线dp,序列自动机 
#include<bits/stdc++.h>
using namespace std;
int T;
string s,t;
int nxt[100005][26];

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>T;
    while(T--){
        bool flag=true;
        cin>>s;
        cin>>t;
        int lens=s.length(),lent=t.length();
        for(int j=0;j<26;j++)    nxt[lens][j]=lens;
        for(int i=lens-1;i>=0;i--)
            for(int j=0;j<26;j++)
            {
                if(s[i]=='a'+j)    nxt[i][j]=i; //nearest position
                else nxt[i][j]=nxt[i+1][j]; // inherit the nearest next[i][j]
            }
            //dp, from the back to the front.
            //next[i][j]=x means that the index x is the nearest position from i,where s[x]=j-'a'.
            //precalculate next[i][j] then solve the problem in O(n)
                        
        int cur=0,ans=1;
        for(int i=0;i<lent;i++){
            int r=t[i]-'a';
            if(nxt[0][r]>=lens){//next position is out of boundary (this character doesn't exist in s)
                flag=false;
                break;
            }
            
            if(nxt[cur][r]>=lens){
                ans++;
                cur=0;
            }
            cur=nxt[cur][r]+1;
        }
        if(flag)    cout<<ans<<'\n';
        else cout<<"-1\n";
    }
    return 0;
}

 

再介绍一个O(nlogn)的暴力做法

只要知道upper_bound这个函数的用法就行了,vector里面存的是字母的位置,纯暴力即可,每次找到末尾就ans++。

具体看代码:

其中pos是字符k在vector里面的位置,ppos是当前已经查找到的s串的位置(类似于一个指针)。

#include<bits/stdc++.h>
using namespace std;
int main() {
    int q;
    cin>>q;
    while(q--) {
        string s,t;
        cin>>s>>t;
        vector<int>p[30];
        for(int i=0; i<s.length(); i++)
            p[s[i]-'a'].push_back(i);
        int ans=1;
        bool flag=true;
        int pos,ppos=-1;
        for(int i=0; i<t.size(); i++) {
            int k=t[i]-'a';
            if(p[k].size()==0) {
                flag=false;
                break;
            }
            pos=upper_bound(p[k].begin(),p[k].end(),ppos)-p[k].begin();
        //    cout<<pos<<endl;
            if(pos==p[k].size()) {
                ans++;
                pos=0;
            }
            ppos=p[k][pos];
        }
        if(!flag)    cout<<"-1\n";
        else cout<<ans<<endl;
    }
}

 

D.Same GCDs

https://codeforces.com/contest/1295/problem/D

题目大意:

已知方程gcd(a,m)=gcd(a+x,m),其中0<=x<m, a和m的规模1e10.

求满足该方程的x的个数。a和m由输入给定,输出x的个数。

 

证明都在代码注释里面了

其实不难 然而蒟蒻当时没开出来qwq

by the way 欧拉函数的定义是:小于或等于x的正整数中与x互质的数的数目,就是代码里面的phi(x)

#include<bits/stdc++.h>
using namespace std;
long long phi(long long x){
    long long ans=x;
    for(long long i=2;i*i<=x;i++){
        if(x%i==0){
            ans=ans/i*(i-1); 
            while(x%i==0) x=x/i;
        }
    }
    if(x>1) ans=ans/x*(x-1);
    return ans;
}

int main()
{
    int t;
    cin>>t;
    while(t--){
        long long a,m;
        cin>>a>>m;
        long long g=__gcd(a,m);
        cout<<phi(m/g)<<endl;
    }
}

/*
Proof:
    gcd(a,m)=gcd(a+x,m),we need to find the number of appropriate x for this equation.
    Let gcd(a,m)=g,then gcd(a,m)=gcd(a+x,m)=gcd((a+x)mod m, m)=g.
    then the answer is sigma(0,m-1)[gcd(i,m)==g],where
        sigma(x,0,m-1)[gcd(a,m)==gcd((a+x)mod m , m)]
    =    sigma(i,1,m)[gcd(i,m)==g]
    =    sigma(i,1,m/g)[gcd(i/g,m/g)==1]...(*)
    According to the definition of Euler's function(phi(x)):
    (*) = phi(m/g).
    So the answer is phi(m/g), where g=gcd(a,m).
*/

 

EF在蒟蒻能力范围之外了,想了解这两题做法敬请移步dalao们的题解。

I wish you all have good luck and high ratings ( ´ ▽ ` )ノ

 

posted @ 2020-02-01 15:28  Doomfist  阅读(166)  评论(0)    收藏  举报