Codeforces Round #818 (Div. 2)(A-E)

Dashboard - Codeforces Round #818 (Div. 2) - CodeforcesCodeforces. Programming competitions and contests, programming communityhttps://codeforces.com/contest/1717

目录

A. Madoka and Strange Thoughts(思维)

B. Madoka and Underground Competitions

C. Madoka and Formal Statement

D. Madoka and The Corruption Scheme

E. Madoka and The Best University


A. Madoka and Strange Thoughts(思维)

题意问1<=a,b<=n的情况下,问存在多少对(a,b)满足lcm(a,b)/gcd(a,b)<=3;

思路:我们把lcm(a,b)/gcd(a,b)中的lcm展开为a*b/gcd(a,b),式子就变成了a/gcd(a,b)*b/gcd(a,b)<=3,已知满足情况的要求,就是a,b分别除以他们的gcd之后,两者相乘<=3,就可推出a=x,b=x或者2*x或者3*x就会满足条件,所以只需要计算该范围内1的倍数,2的倍数和3的倍数个数即可,可以交换的连着的情况就需要*2(a==x,b==x的情况只有一组,其余的可以交换)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N =5e5+10,mod=998244353;
void solve()
{
    int n;
    cin>>n;
    int ans=n/1+n/2*2+n/3*2;
    cout<<ans<<endl;
    return ;
}
signed main()
{
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    int t;
    cin>>t;
    while(t--)
       solve();
    return 0;
}

B. Madoka and Underground Competitions

题意:有一个n*n的图.(n为k倍数),我们想每一个k*1和1*k的子图内只含有一个X,并且确定了一个X的位置,构造出一个符合条件的图.

思路:针对于填写了X的位置所在的k*k的子图(吧n*n分割成很多个k*k的),然后按照规则构造,每一行每一列都有一个X,再把这个小图复制到其他小方图上即可.

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N =5e2+10,mod=998244353;
char ma[N][N];
void solve()
{
    memset(ma,'.',sizeof ma);
    int n,k,r,c;
    cin>>n>>k>>r>>c;
    ma[r][c]='X';
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j+=k)
        {
            int shang=i-r;
            ma[i][j+(c+shang-1+k*500)%k]='X';
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cout<<ma[i][j];
        }
        cout<<endl;
    }
    return ;
}
signed main()
{
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    int t;
    cin>>t;
    while(t--)
       solve();
    return 0;
}

C. Madoka and Formal Statement

题意:给你一个数组a,如果i<n并且a[i]<=a[i+1]那么a[i]就可以变为a[i]+1,i==n的话就和a[1]按照前面的方法比较变换操作(1看做在n后面).问给你的a数组能否变化为b数组.

思路:对于每一位,只需考虑两种情况如果a[i]>b[i],就不合法,如果b[i-1]-b[i]>1也不成立,第一个好理解,因为只能增加,第二个调价那是因为最极限的情况就是b[i]==b[i-1],然后b[i-1]就++,然后b[i-1]就不会发生变化了(除非b[i]改变).

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10,mod=998244353;
int a[N],b[N];
void solve()
{
    int f=0,maxid=-1,maxx=-1;
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
        if(a[i]>=maxx)
        {
            maxx=a[i];
            maxid=i;
        }
    }
    for(int i=0;i<n;i++)
        cin>>b[i];
    for(int i=0;i<n;i++)
    {
        int id=(maxid+i)%n;
        if(b[id]<a[id])
            f=1;
        if(b[(id-1+n)%n]!=a[(id-1+n)%n]&&b[(id-1+n)%n]-b[id]>1)
            f=1;
    }
    if(f)
        cout<<"NO"<<endl;
    else
        cout<<"YES"<<endl;
    return ;
}
signed main()
{
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    int t;
    cin>>t;
    while(t--)
       solve();
    return 0;
}

D. Madoka and The Corruption Scheme

题意:有2^n个人打比赛,用类似于二叉树的形状(每次减少一半)进行比赛配对,最后产生一个胜者.小圆会根据情况尽力安排让获胜者的编号小.然而赞助商有k次机会可以干预某一场比赛的胜负(即吧胜者败者交换).请输出赞助商干预比赛后胜利者的最小的编号.

思路:首先可以知道,如果赞助商干预n场比赛就可以让2^n胜利(每一层的胜负都指向2^n,一共n层).

赞助商是我们的敌人,他们会尽力的把获胜者的编号提升到最大.那么无论他们怎么调整在每一岑个都会有一半的人失败,没经过调整的时候每一层失败的人人的编号都是大于我们每一层的胜利者的,他们有k次调整机会,他们就可以改变失败场次小于等于k的人们的命运.而失败场次大于k的人们因为需要更多次数的调整,就还是无法胜利,要求最小的胜利编号,我们只需要减去那些无法拯救的人的数量即可.所以结果就是(ans=2^n).他们要让最终胜者的编号尽量大,那么就会尽量往编号大了去调整,减去无法被调整成胜者的人数,就是他们能够调整的最大胜者.

for(int i=k+1;i<=n;i++)

        ans=(ans-C(n,i)+mod)%mod;
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N =1e5+10,mod=1e9+7;
int fact[N],infact[N];
int qmi(int x,int y)
{
    int res=1;
    while(y)
    {
        if(y&1)
            res=res*x%mod;
        y>>=1;
        x=x*x%mod;
    }
    return res;
}
void init()
{
    fact[0]=1;
    infact[0]=1;
    for(int i=1;i<=100005;i++)
    {
        fact[i]=fact[i-1]*i%mod;
        infact[i]=infact[i-1]*qmi(i,mod-2)%mod;
    }
    return ;
}
//记录逆元阶乘和阶乘
int C(int x,int y)
{
    return fact[x]*infact[x-y]%mod*infact[y]%mod;
}
void solve()
{
    init();
    int n,k;    
    cin>>n>>k;
    int ans=qmi(2,n);
    for(int i=k+1;i<=n;i++)
        ans=(ans-C(n,i)+mod)%mod;
    cout<<ans<<endl;
    return ;
}
signed main()
{
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    solve();
    return 0;
}

E. Madoka and The Best University

题意:给你a,b,c,满足a+b+c=n,要你计算在这个条件下\sum lcm(c,gcd(a,b));的值.

思路:一开始就想到暴力枚举a,b,c可以确定c,但是n*n不太现实.看大佬枚举的是gcd(a,b),然后去枚举a+b,因为a+b肯定是gcd(a,b)的倍数,所以第二层就是枚举的第一层的倍数.然后根据枚举的a+b(i第一层的倍数)可以求出c,这样复杂度九百年成立nlogn.此时设a=x,b=j-x,c=n-j.

gcd(a,b)=i,i为第一层循环的参数,也就有当前式子,变形:

gcd(x,j-x)=i;

gcd(\frac{x}{i},\frac{j-x}{i})=1

gcd(\frac{x}{i},\frac{j}{i})=1(gcd的性质得来),根据此式子可知,x的取值的方案数就是和(j/i)互质并且比它小的数的个数.这就是欧拉函数的定义,那么a,b的取法就有phi[j/i]种.

所以最后直接预处理欧拉函数直接直接求值:

ans=ans+lcm(i,n-j)*phi[j/i];

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N =1e5+10,mod=1e9+7;
int p[N],phi[N],vis[N],tot=0;
void init()
{
    phi[1]=1;
    for(int i=2;i<=100000;i++)
    {
        if(!vis[i])
        {
            p[tot++]=i;
            phi[i]=i-1;
        }
        for(int j=0;j<tot&&i*p[j]<=100000;j++)
        {
            vis[i*p[j]]=1;
            if(!(i%p[j]))
            {
                phi[i*p[j]]=phi[i]*p[j];
                break;
            }
            phi[i*p[j]]=phi[i]*(p[j]-1);
        }
    }
    return ;
}
void solve()
{
    init();
    int n,ans=0;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        for(int j=2*i;j<n;j+=i)
        {
            ans=(ans+(n-j)*i/__gcd(n-j,i)*phi[j/i])%mod;
        }
    }
    cout<<ans<<endl;
    return ;
}
signed main()
{
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    solve();
    return 0;
}

Xcpc加油啊,大家伙!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值