Educational Codeforces Round 89 (Rated for Div. 2)A、B、C、D、E

[题目](https://codeforces.ml/contest/1366/problem/A)
A题意:两个数a和b,两种操作:1、a减2和b减1。2、a减1和b减2.问最多可以进行多少次操作。
解法:1、如果a>=2b,此时一直进行1操作,最多可操作b次。
2、如果a<2
b,a>b,此时1和2操作配合进行,一定可以达到a+b<3的状态,此时结果就为\(\frac{a+b}{3}\)

void solve(){
    int a , b ;
    cin >> a >> b;
    if(a < b) swap(a,b);
    if(a >= 2*b){
        cout << b << endl;
        return ;
    }
    cout << (a+b)/3 << endl;
}

B题意:给出n个数,初始都为0,只有下标x为1,进行m次操作,每次操作在[l,r]区间内选择两个数交换,问最终状态最多有多少个不同下标位置为1.
解法:如果第x+1次操作区间[q,w]和[l,r]有交集
那么我们的1一定可以从交集处换到[q,w]的每一点去
所以取并集即可

void solve(){
    int n , x , m ;
    cin >> n >> x >> m ;
    int l = x , r = x ;
    rep(i , 1 , m){
        int u , v ;
        cin >> u >> v ;
        if(r < u || l > v) continue;
        l = min(l , u);
        r = max(r , v);
    }
    cout << r - l + 1 << endl;
}

C题意:给出n*m矩阵,矩阵元素为0或1,要求从(1,1)走到(n,m)的所有路径都是对称路径,比如(10101就是对称路径),问最少需要更改几个值。
解法:思路就是所有第k步的值与n+m-k的值相等,所以最小值就是要么将所有0变1.要么所有1变0,min(cnt[k][0]+cnt[n+m-k][0] , cnt[k][1]+cnt[n+m-k][1])。
可以将对称的步数的统计到一边答案直接为min(cnt[k][0] , cnt[k][1]).

const int maxn = 30+9;
int p[maxn<<1][2];
void solve(){
    int n , m ;
    cin >> n >> m ;
    int s = n+m-2;//0-n+m-2共n+m-2步,n-m+1个值(路径长度)
    ME(p , 0);
    rep(i , 0 , n-1){
        rep(j , 0 , m-1){
            int x ;
            cin >> x ;
            if(i+j == (s-i-j)) continue;//对称轴上的值不管
            int r = min(i+j , s-i-j);
            p[r][x]++;
        }
    }
    int ans = 0 ;
    rep(i , 0 , (s+1)/2-1){
        ans += min(p[i][0] , p[i][1]);
    }
    cout << ans << endl;
}

D题意:给出n个数,问每个数是否存在\(d_1|a_i,d_2|a_i,(d_1>1,d_2>1) , gcd(d_1+d_2,a_i)=1\)存在就输出\(d_1,d_2\),否则输出-1,-1.
解法:分析可知\(gcd(d_1,d_2)=1\)(互质),因为如果\(d_1,d_2\)不互质,又有\(d_1|a_i,d_2|a_i\),那么一定\(gcd(d_1+d_2,a_i)!=1\)
埃氏筛法筛出所有数1e7的最小质因子p,如果\(a_i\)只有一个质因子则一定不存在,反则一定存在。
\(d_1 = p, d_2= n除去所有p因子后的值\)

const int N = 1e7+7;
const int maxn = 1e5+9;
int sp[N];
int a[maxn];
void init(){
    sp[1] = 1 ;
    rep(i , 1 , N){
        if(!sp[i]){
            sp[i] = i ;
            for(int j = i*i ; j <= N ; j += i){
                if(!sp[j]) sp[j] = i ;
            }
        }
    }
}
 
void solve(){
    init();
    int n ;
    cin >> n ;
    vector<int>v1 ,v2;
    rep(i , 1 , n){
        int x ;
        cin >> x;
        int di = sp[x];//d1 = p
        int g = x ;
        while(g%di==0){//将n除去所有p因子
            g/=di;
        }
        if(g!=1){//如果n存在不止一个质因子
            v1.pb(g) , v2.pb(di);//d2 = g
        }else{
            v1.pb(-1) , v2.pb(-1);
        }
 
    }
    for(auto i : v1){
        cout << i << " " ;
    }
    cout << endl;
    for(auto i : v2){
        cout << i << " " ;
    }
    cout << endl;
}

E题意:给出两个数组a(1e5)和b,b是递增的给出,问将a分成连续的m段,每一段的最小值等于bi,有多少种分发.
解法:求出a数组的后缀最小值,统计每一个后缀值在所在段,根据分步原理,将段的值依次累乘起来。

const int maxn = 2e5+9;
int a[maxn] , b[maxn] , suf[maxn] , cnt[maxn];
void solve(){
    int n , m ;
    cin >> n >> m ;
    rep(i , 1 , n) cin >> a[i];
    rep(i , 1 , m) cin >> b[i];
    suf[n+1] = 1e9+10;
    red(i , n , 1) suf[i] = min(suf[i+1] , a[i]);
    if(suf[1] != b[1]){
        cout << 0 << endl;
        return ;
    }
    rep(i , 2 , n){
        int p = suf[i];
        int pos = lower_bound(b+1 , b+1+m , p) - b ;
        if(b[pos] == p) cnt[pos]++;//在b数组找到合法段
    }
    int ans = 1 ;
    rep(i , 2 , m){
        ans = ans * cnt[i]%mod;
    }
    cout << ans << endl;
}
posted @ 2020-06-13 11:14  无名菜鸟1  阅读(181)  评论(0编辑  收藏  举报