Educational Codeforces Round 83 (Rated for Div. 2)【ABCDEF】(题解)


涵盖知识点:思维、dp。

比赛链接:传送门

A - Two Regular Polygons

题意: 问你正n边形里能不能套正m边形。
题解: 判断n是不是m倍数即可。
Accept Code:

#include <bits/stdc++.h>
using namespace std;

int main(){
    int t;
    cin>>t;
    while(t--){
        int n,m;
        cin>>n>>m;
        if(n%m==0)puts("YES");
        else puts("NO");
    }
    return 0;
}

B - Bogosort

题意: 重排数组使得不存在一对数满足两者值之差等于下标之差。
题解: 从大到小排序即可,证明随便脑补一下。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn=110;
int a[maxn];
int main(){
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
            cin>>a[i];
        sort(a+1,a+1+n,greater<int>());
        for(int i=1;i<=n;i++){
            cout<<a[i]<<" ";
        }
        cout<<"\n";
    }
    return 0;
}

C - Adding Powers

题意: 给定\(n,k\)和一个全为0的数组,从0开始计数的第\(i\)次操作可以使数组中任意一个数字加\(k^i\),问是否可以构造出要求的新数组。
题解: 枚举要求数组中的所有数字看是否有重复的\(i\)被用到即可。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=110;
ll a[maxn];
set<int> pos;
int n,k;
bool check(){
    pos.clear();
    for(int i=1;i<=n;i++){
        ll x=a[i];
        int d=0;
        while(x){
            if(x%k&&x%k!=1)return false;
            if(x%k==1){
                if(pos.count(d))return false;
                pos.insert(d);
            }
            d++;
            x/=k;
        }
    }
    return true;
}
int main(){
    int t;
    cin>>t;
    while(t--){
        cin>>n>>k;
        for(int i=1;i<=n;i++)
            cin>>a[i];
        puts(check()?"YES":"NO");
    }
    return 0;
}

D - Count the Arrays

题意: 给定\(n,m\),问长度为\(n\),元素限制在\([1,m]\)且必须有且仅有两个元素相同的严格单峰序列能构造出多少个。
题解: 首先在\(m\)个数种选\(n-1\)个,最大的数为峰,剩下\(n-2\)个数字中随便选一个作为相同的那个数字,共\(n\)个数除掉峰值和相等数对剩下\(n-3\)个数,可在左右任意排列。所以\(ans=C_m^{n-1}(n-2)2^{n-3}\)
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int mod=998244353,maxn=2e5+10;
typedef long long ll;
ll qpow(ll a,ll b){
    int res=1;
    while(b){
        if(b&1)res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll fac[maxn];
void init(){
    fac[0]=1;
    for(int i=1;i<maxn;i++){
        fac[i]=fac[i-1]*i%mod;
    }
}
ll c(ll x,ll y){
    return fac[x]*qpow(fac[y]*fac[x-y]%mod,mod-2)%mod;
}
int main(){
    init();
    int n,m;
    cin>>n>>m;
    if(n==2){
        puts("0");
        return 0;
    }
    cout<<((c(m,n-1)*qpow(2,n-3))%mod*1ll*(n-2))%mod<<"\n";
    return 0;
}

E - Array Shrinking

题意: 两个相邻的相同数字可合并为一个大1的数字,问最后能合并成的数组的最小长度。
题解: \(dp_{i,j}\)描述区间\([i,j]\)所能达到的最大数字,处理完以后再扫描一遍区间得出答案。
Accept Code:

#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f,maxn=510;
int a[maxn],ans[maxn],dp[maxn][maxn];
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int i=1;i<=n;i++)
        dp[i][i]=a[i];
    for(int i=n-1;i>=1;i--){
        for(int j=i+1;j<=n;j++){
            for(int k=i;k<j;k++) {
                if (dp[i][k] && dp[k + 1][j] && dp[i][k] == dp[k + 1][j])
                    dp[i][j] = dp[i][k] + 1;
            }
        }
    }
    memset(ans,inf,sizeof ans);
    ans[0]=0;
    for(int i=1;i<=n;i++){
        for(int j=0;j<i;j++)
            if(dp[j+1][i])
                ans[i]=min(ans[i],ans[j]+1);
    }
    cout<<ans[n]<<"\n";
}

F - Attack on Red Kingdom

G - Autocompletion

猜你喜欢

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