Codeforces Round 976 (Div. 2) 題解

arthalter發表於2024-10-03

Codeforces Round 976 (Div. 2) 題解

2020B

一個常見的想法:開關燈=異或,雖然在這道題裡沒啥用
注意到,第i盞燈的按鈕被按的次數就是i的除它本身以外的因子個數
而完全平方數的因子數為奇數,其他數的因子數為偶數

點選檢視更多資訊
#include<bits/stdc++.h>
using namespace std;
void solve()
{
    long long k;
    cin>>k;
    long long n;
    if(k<=100)n=1;
    else n=sqrt(k)-9;

    while(k>n*(n+1))n++;
    cout<<n*n+k-n*(n-1)<<endl;
   
}
int main()
{
    int T;
    cin>>T;
    while(T --> 0)
    {
        solve();
    }
    return 0;
}

2020C

大力分類討論,按位判斷,根據b,c,d的值判斷a的值是可能存在,不存在還是已確定

檢視程式碼
#include<bits/stdc++.h>
using namespace std;
void solve()
{
    long long b,c,d,ck=1;
    cin>>b>>c>>d;
    long long a=0;
    for(long long i=0;i<=60;i++)
    {
        long long tb=b&(1ll<<i);
        long long tc=c&(1ll<<i);
        long long td=d&(1ll<<i);
        if(td==0)
        {
            if(tb!=0&&tc==0)
            {
                ck=0;
                break;
            }else if(tb!=0)
            {
                a+=(1ll<<i);
            }
        }else
        {
            if(tb!=0&&tc==0);
            else if(tb!=0);
            else if(tc!=0)
            {
                ck=0;
                break;
            }else
            {
                a+=(1ll<<i);
            }
        }
    }
    if(ck)cout<<a<<endl;
    else cout<<-1<<endl;
    
}
int main()
{
    long long T;
    cin>>T;
    while(T --> 0)
    {
        solve();
    }
    return 0;
}

2020D

並查集。

注意到:d的範圍很小,而我們只需要知道一個數和它的後十個數之間的聯通關係就可以知道所有點之間的聯通關係。因此我們定義一個n*10的陣列,用來儲存一個數和它之後的第d個數的聯通關係。但是一次操作會影響很多數與它之後的第d個數的關係,我們採用差分的方式進行區間維護

檢視程式碼
#include<bits/stdc++.h>
using namespace std;
int cnt[200005][12];
int f[200005];
int ct[200005];
int find(int x)
{
    if(f[x]==x)return x;
    return f[x]=find(f[x]);
}
void solve()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        f[i]=i;
        ct[i]=0;
        for(int j=1;j<=10;j++)cnt[i][j]=0;
    }
    for(int i=1;i<=m;i++)
    {
        int a,d,k;
        cin>>a>>d>>k;
        cnt[a][d]++;
        cnt[a+k*d][d]--;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=10;j++)
        {
            if(i+j>n)continue;
            if(i>=j)cnt[i][j]+=cnt[i-j][j];
            if(cnt[i][j]>0)f[find(i)]=find(i+j);
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        if(ct[find(i)]==0)ct[find(i)]=1,ans++;
    }
    cout<<ans<<endl;
}
int main()
{
    int T;
    cin>>T;
    while(T --> 0)
    {
        solve();
    }
    return 0;
}

2020E

首先我們需要明白,E(X^2) != E(X)E(X) ,而E(XY)=E(X)E(Y)的前提是X,Y獨立(X,X顯然不獨立)

注意到值域很小,而時限很大,那麼,我們採用一個暴力的想法,定義f[n][x]為前n個數完成選擇後異或和為x的機率,然後所有的f[n][x]xx之和即為答案。

不過這麼開陣列會mle,我們用一個回滾陣列即可

檢視程式碼

#include<bits/stdc++.h>
using namespace std;
int pow(int a,int b,int p)
{
    int s=1;
    while(b)
    {
        if(b%2)s=1ll*s*a%p;
        a=1ll*a*a%p;
        b>>=1;
    }
    return s;
}
int a[200005],b[200005];
const int p=1e9+7;
int f[2][1024];
void solve()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    int m=pow(10000,p-2,p);
    for(int i=1;i<=n;i++)
    {
        cin>>b[i];
        b[i]=1ll*b[i]*m%p;
    }
    for(int j=0;j<=1023;j++)
    {
        f[1][j]=f[0][j]=0;
    }
    f[0][0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=1023;j++)
        {
            f[1][j]=(1ll*f[0][j^a[i]]*b[i]%p+1ll*f[0][j]*(1-b[i]+p)%p)%p;
        }
        for(int j=0;j<=1023;j++)
        {
            f[0][j]=f[1][j];
        }
    }
    long long ans=0;
    for(int i=0;i<=1023;i++)
    {
        ans=(ans+1ll*i*i%p*f[0][i]%p)%p;
    }
    cout<<ans<<endl;

}
int main()
{
    int T;
    cin>>T;
    while(T --> 0)
    {
        solve();
    }
    return 0;
}


2020F

還沒改出來,先咕咕咕

相關文章