首页 > 其他分享 >Codeforces Round 976 (Div. 2)

Codeforces Round 976 (Div. 2)

时间:2024-10-01 14:33:40浏览次数:1  
标签:976 题意 int void Codeforces cdot vector Div dp

VP 的这一场,真的唐完了。。。

A. Find Minimum Operations

题意

给你一个 \(n\) 和 \(k\) ,每次操作可以让 \(n\) 减去一个 \(k\) 的 \(x\) 次方,即 \(n-k^x\)。问你最少操作几次能够让 \(n\) 变成 \(0\) 。

思路

我们先考虑如果 \(k\) 是 \(2\) 的情况,那么题目就转化成了 \(n\) 的二进制中 \(1\) 的个数。扩展到任意进制的话就是把 \(n\) 转化为 \(k\) 进制,每次操作可以使一个 \(k\) 进制数位上的数减 \(1\) 。于是我们只要把 \(n\) 转化为 \(k\) 进制,然后把每个数位上的数加起来即可。

代码

void solve()
{
    int n,k,ans=0;
    cin>>n>>k;
    if(k==1) {return cout<<n<<endl,void();}
    while(n)
    {
        ans+=n%k;
        n/=k;
    }
    cout<<ans<<endl;
}

B. Brightness Begins

题意

假设你有 \(n\) 个初始状态为亮的灯泡,接下来你要执行一下操作:

  • 对于每个 \(i=1,2...n\) 反转所有灯牌 \(j\) 的状态,\(j\) 是可以被 \(i\) 整除的数。

执行完所有操作后,你希望亮着的灯泡数量为 \(k\) 。现在给你一个 \(k\) ,问你 \(n\) 最小可以是多少。

思路

这种题我一般先想到打表找规律,看看每个 \(n\) 对应的最后的状态。打出来的表如下

0 
0 1 
0 1 1 
0 1 1 0 
0 1 1 0 1 
0 1 1 0 1 1 
0 1 1 0 1 1 1 
0 1 1 0 1 1 1 1 
0 1 1 0 1 1 1 1 0 
0 1 1 0 1 1 1 1 0 1 
0 1 1 0 1 1 1 1 0 1 1 
0 1 1 0 1 1 1 1 0 1 1 1 
0 1 1 0 1 1 1 1 0 1 1 1 1 
0 1 1 0 1 1 1 1 0 1 1 1 1 1 
0 1 1 0 1 1 1 1 0 1 1 1 1 1 1 
0 1 1 0 1 1 1 1 0 1 1 1 1 1 1 0 
0 1 1 0 1 1 1 1 0 1 1 1 1 1 1 0 1 
0 1 1 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 
0 1 1 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 
0 1 1 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 
0 1 1 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 
0 1 1 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 

我们发现前面的灯泡状态是固定的,然后每几个连续的 \(1\) 之间都会有一个 \(0\) 隔开,并且发现连续的 \(1\) 的数量是 \(2,4...2\cdot n\) ,一个公差为 \(2\) 的等差数列。于是我们就考虑 \(k\) 在哪一段区间内,最终的答案就是 \(k\) 所在的区间加上 \(k\) 即可。找区间的过程用个二分就行了。

代码

注释掉的内容为打表代码

void solve()
{
    // int n;
    // cin>>n;
    // vector<int> a(n+1,1);
    // for(int i=1;i<=n;i++)
    // {
    //     for(int j=1;j<=n;j++)
    //         if(j%i==0) a[j]^=1;
    // }
    // int num=0;
    // for(int i=1;i<=n;i++)  if(a[i]) num++;
    // cout<<num<<endl;
    // for(int i=1;i<=n;i++) cout<<a[i]<<' ';
    // cout<<endl;
    int k;
    cin>>k;
    int l=1,r=k;
    while(l<r)
    {
        __int128_t mid=l+r>>1;//这里要注意等差数列求和的时候要开int128,我就是因为这里WA了
        if((mid+1)*mid>=k) r=mid;
        else l=mid+1;
    }
    cout<<l+k<<endl;
}

C. Bitwise Balancing

题意

给你三个非负整数 \(b,c,d\) 让你找到一个 \(a\) 满足 \(a|b - a \&c=d\) 。

思路

这题我VP的时候真的是唐完了。。。
一开始判少了条件,之后忘了 \(\text{long long}\),\(\text{WA}\) 了 \(8\) 发。
img

首先按位考虑, \(a\) 的每一位应该怎么填。枚举 \(b,c,d\) 每一位填什么,把 \(8\) 种情况全部列举出来特判一下即可。

代码

void solve()
{
    int b,c,d,flag=0;
    cin>>b>>c>>d;
    int ans=0;
    for(int i=0;i<=60;i++)
    {
        int num=1ll<<i;//这里我是真的唐完了,每次都忘记1是一个int类型,要写1ll才行
        int x=b&num,y=c&num,z=d&num;
        if(!x && !y && z) ans|=num;
        if(!x && y && z) return cout<<-1<<endl,void();
        if(x && !y && !z) return cout<<-1<<endl,void();
        if(x && y && !z) ans|=num;
    }
    cout<<ans<<endl;
}

D. Connect the Dots

题意

给你一个长度为 \(n\) 的序列和 \(m\) 次操作。操作如下:

  • 选择三个整数 \(a_i,d_i(1\leq d\leq 10),k_i\) 。
  • 把 \(a_i,a_i+d_i,a_i+2d_i...a_i+k\cdot d_i\) 添加到同一个集合里。

问你 \(m\) 次操作结束后一共有多少个不同的集合。

思路

注意到, \(d\) 的范围很小,我们可以对于每一个 \(d\) 分别考虑。又因为是区间修改最后才查询,于是我一开始想的是差分,把初始位置和最后位置分别 \(+1\) , \(-1\) ,然后 \(i\) 从 \(i-d\) 转移过来,把这两个位置放到一个集合里。但是这样有一个问题,我无法判断出当前这个区间左端点和前一个区间的右端点是不是在同一个区间里面。于是我发现可以直接记录当前这个点向后最大更新的次数,如果 \(i-d\) 还能继续向后更新,那么就把 \(i\) 和 \(i-d\) 放到同一个集合, \(i\) 更新的次数和 \(i-d\) 更新的次数取个 \(max\) 即可。对于每个 \(d\) 都操作一下,时间复杂度 \(O(10\cdot n)\) 。

代码

void solve()
{
    int n,m;
    cin>>n>>m;
    vector cha(n+100,vector<int>(11));
    vector<int> fa(n+1);
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=m;i++)
    {
        int a,d,k;
        cin>>a>>d>>k;
        cha[a][d]=max(cha[a][d],k);
    }
    function<int(int)> getfa=[&](int x)
    {
        if(x==fa[x]) return x;
        return fa[x]=getfa(fa[x]);
    };
    auto merge=[&](int x,int y)
    {
        int fx=getfa(x),fy=getfa(y);
        if(fx==fy) return;
        fa[fy]=fx;
    };
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=10;j++)
        {
            if(i-j<0) continue;
            if(cha[i-j][j]) merge(i,i-j);
            cha[i][j]=max(cha[i-j][j]-1,cha[i][j]);
        }
    }
    int cnt=0;
    vector<int> vis(n+1);
    for(int i=1;i<=n;i++) if(!vis[getfa(i)]){vis[getfa(i)]=1,cnt++;}
    cout<<cnt<<endl;
}

E. Expected Power

题意

给你 \(n\) 个数 \(a_i (1\leq a_i\leq 1024)\) ,每个数都有 \(\frac{p_i}{10^4}\) 的概率添加到多集 \(S\) 中。 \(f(S)\) 表示 \(S\) 集合中所有数的异或和,让你求出 \((f(S))^2\) 的期望,结果对 \(10^9\) 取模。

思路

一遇到这种异或的问题我就想到拆位,很可惜这题不是。注意到 \(a_i\) 的数据范围很小,我们可以枚举 \(f(S)\) 的值,不会超过 \(1024\) 。然后计算概率,对于每个 \(a_i\) 有 \(p_i\) 的概率选和 \(p_i\) 的概率不选,那么转移方程就出来了 \(dp_{i,j}+=dp_{i-1,j}\cdot (1-p_i)+dp_{i-1,j\oplus a_i}\cdot p_i\) 。
然后每个 \(i\) 都是从 \(i-1\) 转移而来,可以用滚动数组优化空间。时间复杂度 \(O(1024\cdot n)\)。

代码

void solve()
{
    int n,inv=qpow(10000,mod-2);
    cin>>n;
    vector<int> a(n+1),p(n+1),dp(1024);
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) cin>>p[i];
    dp[0]=1;
    for(int i=1;i<=n;i++)
    {
        vector<int> g(1024);
        for(int j=0;j<1024;j++)
        {
            g[j]=(g[j]+dp[j]*(10000-p[i])%mod)%mod;
            g[j]=(g[j]+dp[j^a[i]]*p[i]%mod)%mod;
        }
        for(int j=0;j<1024;j++) g[j]=g[j]*inv%mod;
        dp=g;
    }
    int ans=0;
    for(int i=0;i<1024;i++)
    {
        int temp=i*i%mod;
        ans+=temp*dp[i]%mod;
        ans%=mod;
    }
    cout<<ans<<endl;
}

标签:976,题意,int,void,Codeforces,cdot,vector,Div,dp
From: https://www.cnblogs.com/Lao-Die/p/18442861

相关文章

  • Codeforces Round 958 (Div. 2)
    手速前三题,D题想到树形dp但是没做出来。A.SplittheMultiset题意给你一个多集,一开始这个多集里只有一个数字。每次操作可以选择删掉多集里的一个数,然后添加\(k\)个数,并且使得这\(k\)个数的和等于删掉的数。问你最少需要操作多少次多集里的数的个数等于等于\(n\)。思路......
  • codeforces round 975 E(div.2)(lambda表达式实现dfs,min_element函数,一定要优化重复的
    解题历程:看到题目要求要用最少的消除次数让所有叶子深度相同,通过观察,那么就只需要将所有深度都尝试一遍就行了,可是我当时没多想就用dfs记录所有节点的深度,单独将所有叶子和该叶子的深度存起来,记录最大的深度,从最大深度尝试到深度0,对于深度小于当前尝试深度的叶子,用dfs的方式将与......
  • Codeforces Round 976 (Div. 2) and Divide By Zero 9.0
    目录写在前面A签到B数学,模拟C二进制,拆位D暴力,并查集E概率DPF写在最后写在前面补题地址:https://codeforces.com/gym/104128。上大分失败呃呃呃呃有点过载了妈的我现在应该去打会儿游戏。A签到等价于求\(n\)在\(k\)进制下各位之和,写一个类似快速幂的东西。///*By......
  • Codeforces Round 975 (Div. 2)
    C.CardsPartition(C)对于每个确定的size,有便捷的方法判断该值是否合法:组数最小为\(a_{max}\),若\(k\)张牌可以填出\(a_{max}\)组牌堆则合法;将余下的牌当成新的一组,若\(k\)张牌可以凑出一整组则合法;其余情况不合法。由于check过程为\(O(1)\),可从大到小暴力枚举size,时间......
  • Codeforces Round 976 (Div. 2)
    传送门A.输出\(n\)在\(k\)进制下各数位之和B.一个位置被反转当且仅当有奇数个因子,有奇数个因子的数一定是完全平方数。二分\(n\)即可C.枚举二进制下每一位,发现\(b,c,d\)再这一位最多有八种可能,对于每一种情况都能得到在这一位\(a\)的值,分类讨论就行了。D.E.\(......
  • Codeforces Round 976 (Div. 2)
    B:很容易发现只有因数个数为偶数的灯泡是亮的。所以只有完全平方数的因数是奇数个。实现上可以二分。但是sqrt是double的必须开sqrtl才是longdouble的,才能满足这题longlong的数据范围。人给我卡傻了。哈哈。#include<bits/stdc++.h>usingnamespacestd;#defineintunsign......
  • Codeforces Round 975 (Div. 2) CE
    来源:CodeforcesRound975(Div.2)C.CardsPartition题意本身有\(a_i\)张\(i\)牌,现在将牌分成若干份,每一份牌数相等,且每一份都由不同的牌组成同时有\(k\)次补充任意牌的机会,求最多分成一份几张牌思路假定分成\(m\)份,每份\(p\)张牌,那么所有牌加补充的牌等于\(m*p......
  • Codeforces Round 975 (Div. 2) A~F 题解(Div.1 A~D)
    CodeforcesRound975(Div.2)A~F题解(Div.1A~D)也是补完整场了。A.MaxPlusSize枚举最大值的位置,使长度最长,更新答案。B.AllPairsSegments每个线段内部的点的答案都是一样的,在处理一下线段两边边界的点。被包含次数就是左边\(\times\)右边。用\(map\)记录答案......
  • Codeforces Round 975 (Div. 2)
    目录写在前面A签到B排序,模拟C数学,贪心D模拟,思维E树,贪心,暴力or长链剖分F贪心,枚举写在最后写在前面比赛地址:https://codeforces.com/contest/2019。唉唉不敢打div1只敢开小号打div2太菜了。A签到显然最优方案只有两种——取所有奇数位置或所有偶数位置。///*By......
  • Codeforces Round 975 (Div. 2) A-E
    人生中第一次正常\(div2\)爆写5题。cf给我正反馈最大的一次A直接找到最大的数字的位置,然后判断一下这个数字的位置下标的奇偶性就好了。然后如果有多个最大的就取奇数位置的。这样可以算出来一定是最优解#include<bits/stdc++.h>#definelllonglongusingnamespacestd;inl......