Codeforces Round #730 (Div. 2) A/B/C/D1 解题思路

好久没敲代码了,连写D1这简单题脑子都转不过来唉,属实一段时间不碰直接成菜鸡了

只写了A/B/C/D1四题,体力也快跟不上了,还剩五十分钟不大想看题了

当作康复训练吧(逃

pic


A - Exciting Bets

A. Exciting Bets

题意

给你两个数字 a , b a,b a,b

每次你可以让两个数都 + 1 +1 +1或者 − 1 -1 1,但不能出现负数

使得最终的 gcd ⁡ ( a , b ) \gcd(a,b) gcd(a,b)尽可能大,并且操作次数尽可能小

输出最大的 gcd ⁡ ( a , b ) \gcd(a,b) gcd(a,b)可能值,并且输出获得这个值的最小操作数

如果 gcd ⁡ ( a , b ) \gcd(a,b) gcd(a,b)的最大值是无限大,则输出“ 0   0 0\ 0 0 0

特殊的, gcd ⁡ ( x , 0 ) = x \gcd(x,0)=x gcd(x,0)=x

思路

很明显只有当 a = b a=b a=b成立时, gcd ⁡ ( a , b ) \gcd(a,b) gcd(a,b)才会接近无限大

而对于 a ≠ b a\neq b a=b的情况, gcd ⁡ \gcd gcd的最大值也就是 ∣ a − b ∣ |a-b| ab

对于最小的操作数,只需要让 a , b a,b a,b都变成 ∣ a − b ∣ |a-b| ab的倍数即可

向下移动次数即 a % ( a − b ) a\%(a-b) a%(ab),向上移动次数即对除数取补,即 ( a − b ) − a (a-b)-a%(a-b) (ab)a

两者取小即可

代码

//#include<ext/pb_ds/assoc_container.hpp>
//#include<ext/pb_ds/hash_policy.hpp>
#include<bits/stdc++.h>
#define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define multiCase int T;cin>>T;for(int t=1;t<=T;t++)
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define perr(i,a,b) for(int i=(a);i>(b);i--)
#define all(a) (a).begin(),(a).end()
#define mst(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define eb emplace_back
#define fi first
#define se second
using namespace std;
//using namespace __gnu_pbds;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> P;
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;
const double eps=1e-12;
const double PI=acos(-1.0);
const ll mod=998244353;
const int dx[8]={0,1,0,-1,1,1,-1,-1},dy[8]={1,0,-1,0,1,-1,1,-1};
mt19937 mt19937random(std::chrono::system_clock::now().time_since_epoch().count());
ll getRandom(ll l,ll r){return uniform_int_distribution<ll>(l,r)(mt19937random);}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll qmul(ll a,ll b){ll r=0;while(b){if(b&1)r=(r+a)%mod;b>>=1;a=(a+a)%mod;}return r;}
ll qpow(ll a,ll n){ll r=1;while(n){if(n&1)r=(r*a)%mod;n>>=1;a=(a*a)%mod;}return r;}
ll qpow(ll a,ll n,ll p){ll r=1;while(n){if(n&1)r=(r*a)%p;n>>=1;a=(a*a)%p;}return r;}



void solve()
{
    ll a,b;
    cin>>a>>b;
    if(a>b)swap(a,b);
    if(a==b)
        cout<<"0 0\n";
    else
        cout<<b-a<<' '<<min(a%(b-a),(b-a)-a%(b-a))<<'\n';
}
int main()
{
    closeSync;
    multiCase
    {
        solve();
    }
    return 0;
}

B - Customising the Track

B. Customising the Track

题意

给定一个长度为 n n n的数组 { a } \{a\} {a}

每次可以随意选择两个位置,让其中一个 − 1 -1 1,另一个 + 1 +1 +1,操作次数不限

要求最终 ∑ i = 1 n ∑ j = i + 1 n ∣ a i − a j ∣ \sum_{i=1}^n\sum_{j=i+1}^n|a_i-a_j| i=1nj=i+1naiaj最小,并求出这个最小值

思路

可得均分所有位置的值时,答案最小

求出总和 s s s,与 n n n取模得到无法平均分配的值的大小 d = s % n d=s\%n d=s%n

那么选择 d d d个位置均分这些值

则题目中公式的值也就是此时有多少对位置的值是不同的

值为 s / n s/n s/n的位置有 n − d n-d nd个,值为 s / n + 1 s/n+1 s/n+1的位置有 d d d

答案即 d ∗ ( n − d ) d*(n-d) d(nd)

代码

//#include<ext/pb_ds/assoc_container.hpp>
//#include<ext/pb_ds/hash_policy.hpp>
#include<bits/stdc++.h>
#define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define multiCase int T;cin>>T;for(int t=1;t<=T;t++)
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define perr(i,a,b) for(int i=(a);i>(b);i--)
#define all(a) (a).begin(),(a).end()
#define mst(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define eb emplace_back
#define fi first
#define se second
using namespace std;
//using namespace __gnu_pbds;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> P;
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;
const double eps=1e-12;
const double PI=acos(-1.0);
const ll mod=998244353;
const int dx[8]={0,1,0,-1,1,1,-1,-1},dy[8]={1,0,-1,0,1,-1,1,-1};
mt19937 mt19937random(std::chrono::system_clock::now().time_since_epoch().count());
ll getRandom(ll l,ll r){return uniform_int_distribution<ll>(l,r)(mt19937random);}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll qmul(ll a,ll b){ll r=0;while(b){if(b&1)r=(r+a)%mod;b>>=1;a=(a+a)%mod;}return r;}
ll qpow(ll a,ll n){ll r=1;while(n){if(n&1)r=(r*a)%mod;n>>=1;a=(a*a)%mod;}return r;}
ll qpow(ll a,ll n,ll p){ll r=1;while(n){if(n&1)r=(r*a)%p;n>>=1;a=(a*a)%p;}return r;}



void solve()
{
    int n;
    cin>>n;
    ll s=0;
    rep(i,1,n)
    {
        int d;
        cin>>d;
        s+=d;
    }
    s%=n;
    cout<<s*(n-s)<<'\n';
}
int main()
{
    closeSync;
    multiCase
    {
        solve();
    }
    return 0;
}

C - Need for Pink Slips

C. Need for Pink Slips

题意

有三个字母 C / M / P C/M/P C/M/P,初始时每个字母被选中的次数分别为 c , m , p   ( c + m + p = 1 ) c,m,p\ (c+m+p=1) c,m,p (c+m+p=1)

还有一个浮动指数 v   ( 0.1 ≤ v ≤ 0.9 ) v\ (0.1\le v\le 0.9) v (0.1v0.9)

每次会根据概率随机抽取一个字母,规则如下:

  • 如果抽到字母 P P P,游戏结束
  • 否则,根据抽到的那个字母所对应的概率 a a a,与浮动指数 v v v进行比对
    • 如果 a ≤ v a\le v av,则这个字母接下来抽到的概率变为 0 0 0,且不再会受到后续操作的影响导致概率上升(变成不可用字母),其概率将被均匀分配给剩余的可用字母
    • 如果 a > v a\gt v a>v,则这个字母接下来抽到的概率将会减 v v v a : = a − v a:=a-v a:=av),被减去的概率将被均匀分配给剩余的可用字母

问随机进行抽取游戏,最终抽到的字母个数的期望值是多少

思路

发现 0.1 ≤ v ≤ 0.9 0.1\le v\le 0.9 0.1v0.9,这个值的精度很粗略,并且抽到 P P P就会结束游戏,每次平均分配概率都会给 P P P分配到,所以可以直接 d f s dfs dfs模拟一遍全过程,状态数不会太多

d f s ( c , m , p , l e n , c u r p ) dfs(c,m,p,len,curp) dfs(c,m,p,len,curp)的传参分别表示当前抽到 C / M / P C/M/P C/M/P的概率、已经抽到的字母数量、处理到当前状态的概率

注意题目中给定的条件,一旦某个字母变成不可用字母,其后进行的分配概率的操作将不会考虑它

那么直接模拟,假设当前抽到字母 C C C,概率就是 c u r p ∗ c curp*c curpc C C C的概率变成 m a x ( c − v , 0 ) max(c-v,0) max(cv,0),而减去的部分平分给剩余的可用字母,继续搜索下去

抽到字母 M M M的情况同 C C C

假如抽到 P P P,则不会再有新的子状态产生,此时概率也就是 c u r p ∗ p curp*p curpp,加上 P P P后字母个数为 l e n + 1 len+1 len+1,则对答案的贡献也就是 ( l e n + 1 ) ∗ c u r p ∗ p (len+1)*curp*p (len+1)curpp

代码

//#include<ext/pb_ds/assoc_container.hpp>
//#include<ext/pb_ds/hash_policy.hpp>
#include<bits/stdc++.h>
#define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define multiCase int T;cin>>T;for(int t=1;t<=T;t++)
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define perr(i,a,b) for(int i=(a);i>(b);i--)
#define all(a) (a).begin(),(a).end()
#define mst(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define eb emplace_back
#define fi first
#define se second
#define double long double
using namespace std;
//using namespace __gnu_pbds;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> P;
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;
const double eps=1e-14;
const double PI=acos(-1.0);
const ll mod=998244353;
const int dx[8]={0,1,0,-1,1,1,-1,-1},dy[8]={1,0,-1,0,1,-1,1,-1};
mt19937 mt19937random(std::chrono::system_clock::now().time_since_epoch().count());
ll getRandom(ll l,ll r){return uniform_int_distribution<ll>(l,r)(mt19937random);}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll qmul(ll a,ll b){ll r=0;while(b){if(b&1)r=(r+a)%mod;b>>=1;a=(a+a)%mod;}return r;}
ll qpow(ll a,ll n){ll r=1;while(n){if(n&1)r=(r*a)%mod;n>>=1;a=(a*a)%mod;}return r;}
ll qpow(ll a,ll n,ll p){ll r=1;while(n){if(n&1)r=(r*a)%p;n>>=1;a=(a*a)%p;}return r;}

double v,r=0;

void dfs(double c,double m,double p,int len,double curp)
{
    if(c>eps) //假设抽到了C
    {
        double d=max(c-v,(double)0.0); //c接下来的概率
        if(m>eps) //假如M是可用字母,则概率平分给M和P
            dfs(d,m+(c-d)/2,p+(c-d)/2,len+1,curp*c);
        else //否则概率全部给P
            dfs(d,m,p+(c-d),len+1,curp*c);
    }
    if(m>eps) //假设抽到了M,下同
    {
        double d=max(m-v,(double)0.0);
        if(c>eps)
            dfs(c+(m-d)/2,d,p+(m-d)/2,len+1,curp*m);
        else
            dfs(c,d,p+(m-d),len+1,curp*m);
    }
    //cout<<c<<' '<<m<<' '<<p<<' '<<len<<' '<<curp<<'\n';
    r+=p*(len+1)*curp; //假如抽到了P,直接计算对答案的贡献
}

void solve()
{
    double c,m,p;
    cin>>c>>m>>p>>v;
    r=0;
    dfs(c,m,p,0,1.0);
    cout<<fixed<<setprecision(12)<<r<<'\n';
}
int main()
{
    closeSync;
    multiCase
    {
        solve();
    }
    return 0;
}

D1 - RPD and Rap Sheet (Easy Version)

D1. RPD and Rap Sheet (Easy Version)

题意

交互题

初始时给定两个数 n , k n,k n,k

在本Version中 k = 2 k=2 k=2恒定,此值无关紧要,下文直接以异或代替

要求猜测一个位于 0 0 0 n − 1 n-1 n1之间的数 x x x,最多只能猜 n n n

对于每次猜测的数字 y y y

  • 假如 x = y x=y x=y,系统输出 1 1 1,表示猜测成功,结束本次猜测
  • 否则,系统输出 0 0 0,并且此时 x x x的值将会变成 z z z,并且 z z z满足 x ⊕ z = y x\oplus z=y xz=y

思路

x ⊕ z = y x\oplus z=y xz=y,即 x ⊕ z ⊕ x = y ⊕ x x\oplus z\oplus x=y\oplus x xzx=yx,即 z = x ⊕ y z=x\oplus y z=xy

即对于每次猜测,会将待猜测的值 x x x与猜测的值 y y y取二进制异或,形成新的 x x x

那么初始时先猜 0 0 0,如果成功直接退出,失败的话继续接下来的操作

由于初始 x x x的值保证在 0 0 0 n − 1 n-1 n1之内,最多也只能猜 n n n次,所以从某种意义上来说直接枚举一遍 0 0 0 n − 1 n-1 n1之间的数即可

从第二次猜测开始,每次猜测将前一次猜测所造成的影响除去

根据 a ⊕ b ⊕ b = a a\oplus b\oplus b=a abb=a,所以接下来枚举 i = 1 i=1 i=1 n − 1 n-1 n1,每次猜测的数为 i ⊕ ( i − 1 ) i\oplus (i-1) i(i1),就可以将 i − 1 i-1 i1造成的影响删除,变为猜测数字 i i i

代码

//#include<ext/pb_ds/assoc_container.hpp>
//#include<ext/pb_ds/hash_policy.hpp>
#include<bits/stdc++.h>
#define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define multiCase int T;cin>>T;for(int t=1;t<=T;t++)
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define perr(i,a,b) for(int i=(a);i>(b);i--)
#define all(a) (a).begin(),(a).end()
#define mst(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define eb emplace_back
#define fi first
#define se second
using namespace std;
//using namespace __gnu_pbds;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> P;
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;
const double eps=1e-12;
const double PI=acos(-1.0);
const ll mod=998244353;
const int dx[8]={0,1,0,-1,1,1,-1,-1},dy[8]={1,0,-1,0,1,-1,1,-1};
mt19937 mt19937random(std::chrono::system_clock::now().time_since_epoch().count());
ll getRandom(ll l,ll r){return uniform_int_distribution<ll>(l,r)(mt19937random);}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll qmul(ll a,ll b){ll r=0;while(b){if(b&1)r=(r+a)%mod;b>>=1;a=(a+a)%mod;}return r;}
ll qpow(ll a,ll n){ll r=1;while(n){if(n&1)r=(r*a)%mod;n>>=1;a=(a*a)%mod;}return r;}
ll qpow(ll a,ll n,ll p){ll r=1;while(n){if(n&1)r=(r*a)%p;n>>=1;a=(a*a)%p;}return r;}



void solve()
{
    int n,k,r;
    scanf("%d%d",&n,&k);
    
    printf("0\n"); //先猜0
    fflush(stdout);
    scanf("%d",&r);
    if(r==1)
        return;
    
    repp(i,1,n) //枚举一遍总能猜到
    {
        printf("%d\n",i^(i-1)); //其后每次注意去除前一次造成的影响即可
        fflush(stdout);
        scanf("%d",&r);
        if(r==1)
            break;
    }
    fflush(stdout);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
        solve();
    return 0;
}

D2/E 无


https://www.cnblogs.com/stelayuri/p/14984345.html


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值