Codeforces Round #499 (Div. 2)(D、E、F


D.Rocket

题意:

交互题

给定m和n,要求你猜一个x,x的范围在1到m内
给机器人y,如果x<y则返回-1,如果x>y则返回1,如果x=y则返回0,
但是机器人有故障,有可能返回错误的答案
机器人内部有一个长度为n的序列p,p(i)只有0和1两种取值,玩家是不知道p中的元素值的。
第i次问机器人的时候,假设应该返回的答案是t,如果p(i)=1,那么机器人会回答-t,如果p(i)=0,那么机器人会回答t

现在要你在60次询问之内,问出x的值。

数据范围:m<=1e9,n<=30

解法:

如果没有真假话系统的话,显然可以直接二分。

考虑到当我们问机器人1的时候:
1.如果x=1,那么机器人会返回0,0的时候一定是真话,因此答案就出来了
2.如果x!=1,因为x是在1到m范围内的,那么x一定大于1,
这时候如果机器人返回1,表明这时候的是真话,p(i)=1,反之如果返回-1则p(i)=0

这样我们就能用n次测试测数p数组,然后二分就行了(用p数组来获得正确回答)。
因为230大于1e9,因此一定能在30次之内测出来

code:

#include<bits/stdc++.h>
using namespace std;
const int maxm=35;
int p[maxm];
signed main(){
    int m,n;
    cin>>m>>n;
    int x;
    for(int i=0;i<n;i++){
        cout<<1<<endl;
        cin>>x;
        if(x==1)p[i]=1;
        else p[i]=0;
    }
    int l=2,r=m;
    int now=0;
    while(x!=0){
        int mid=(l+r)/2;
        cout<<mid<<endl;
        cin>>x;
        if(!p[now++])x=-x;
        now%=n;//记得取模
        if(x==1)l=mid+1;
        else r=mid-1;
    }
    return 0;
}

E.Border

题意:

给一个长度为n的数组a,和一个整数k。
你可以选择数组中的任意数相加(每个数无限个,可任选),问相加的结果k进制最后一位有多少种情况。
输出所有情况。

解法:

裴蜀定理(贝祖定理):若a,b是整数,且gcd(a,b)=d,那么对于任意的整数x,y,ax+by都一定是d的倍数,特别地,一定存在整数x,y,使ax+by=d成立。
它的一个重要推论是:a,b互质的充要条件是存在整数x,y使ax+by=1.

n个整数间的裴蜀定理:设a1,a2,a3…an为n个整数,d是它们的最大公约数,
那么存在整数x1…xn使得x1a1+x2a2+…xnan=d。
特别来说,如果a1…an互质(不是两两互质),那么存在整数x1…xn使得x1a1+x2a2+…xnan=1。

这道题的解法
假设第i个数用xi次,这些数相加就是式子x1a1+x2a2+…xnan,
由裴蜀定理可知:设a1,a2,a3…an的最大公约数为d,那么上面的式子结果一定是d的倍数,
因为是在模k意义下,因此计算出d,在0到k-1范围内枚举倍数即可(k对k取模就变成0了,因此只枚举到k-1)

code:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}
signed main(){
    int n,k;
    cin>>n>>k;
    int gg=0;
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        gg=gcd(gg,x);
    }
    gg%=k;
    set<int>ans;
    for(int i=0;i<k;i++){
        ans.insert(gg*i%k);
    }
    cout<<ans.size()<<endl;
    for(int v:ans)cout<<v<<' ';
    return 0;
}

F.Mars rover

题面:

在这里插入图片描述
在这里插入图片描述

题意:

给一颗树,1为根,每个节点最多两个子节点,每个非叶子点有与、或、非、异或,这4种操作的其中一种(如图),
叶子节点有一个一比特的初值0或者1,然后不断向上按节点操作传递到根,从根节点输出数据。
现在问每个叶子节点如果初值改变,那么根节点的数据是多少,每次叶子节点改变是独立的。
输出每个叶子节点改变后根结点的输出。

思路:

如果每次都修改叶子节点然后在从下向上上传数据,显然是不行的。

先计算出叶子不改变的情况下,每个节点的值,一次dfs就可以求出
从根开始向下检测,假如根是and,
如果根的值为1,那么左右节点改变都会影响根节点的答案,那么处理左右节点
如果根的值为0,假设左右节点为0,1,那么值为0的节点改变会影响根的答案,那么递归处理制为0的节点

其他情况类似,即只向有可能影响到根的节点进行dfs搜索,如果搜到了叶子节点,那么标明这个叶子会影响根
这样的话一次dfs就能计算出哪些叶子节点的改变会影响根了。

code:

#include<bits/stdc++.h>
using namespace std;
const int maxm=1e6+5;
vector<int>g[maxm];
int mark[maxm];
int d[maxm];//操作符
int v[maxm];//值
int n;
/*
and 1
or 2
xor 3
not 4
in 5
*/
int dfs(int x){//计算出初始情况每个节点的值
    if(d[x]==1)return v[x]=dfs(g[x][0])&dfs(g[x][1]);
    else if(d[x]==2)return v[x]=dfs(g[x][0])|dfs(g[x][1]);
    else if(d[x]==3)return v[x]=dfs(g[x][0])^dfs(g[x][1]);
    else if(d[x]==4)return v[x]=!dfs(g[x][0]);
    else return v[x];
}
void dfs2(int x){
    if(d[x]==1){//and
        if(v[x]==1){//两个子节点改变会造成影响
            dfs2(g[x][0]);
            dfs2(g[x][1]);
        }else{
            if(!v[g[x][0]]&&v[g[x][1]])dfs2(g[x][0]);//第一个改变会有影响
            if(v[g[x][0]]&&!v[g[x][1]])dfs2(g[x][1]);//第二个改变会有影响
        }
    }else if(d[x]==2){//or
        if(v[g[x][0]]&&!v[g[x][1]])dfs2(g[x][0]);
        if(!v[g[x][0]]&&v[g[x][1]])dfs2(g[x][1]);
        if(!v[g[x][0]]&&!v[g[x][1]]){
            dfs2(g[x][0]);
            dfs2(g[x][1]);
        }
    }else if(d[x]==3){//xor
        dfs2(g[x][0]);
        dfs2(g[x][1]);
    }else if(d[x]==4){//not
        dfs2(g[x][0]);
    }else if(d[x]==5){//in
        mark[x]=1;//这个叶子改变会改变根
    }
}
signed main(){
    ios::sync_with_stdio(0);cin.tie(0);
    cin>>n;
    string s;
    int l,r;
    for(int i=1;i<=n;i++){
        cin>>s;
        if(s[0]=='A'){
            d[i]=1;
            cin>>l>>r;
            g[i].push_back(l);
            g[i].push_back(r);
        }else if(s[0]=='O'){
            d[i]=2;
            cin>>l>>r;
            g[i].push_back(l);
            g[i].push_back(r);
        }else if(s[0]=='X'){
            d[i]=3;
            cin>>l>>r;
            g[i].push_back(l);
            g[i].push_back(r);
        }else if(s[0]=='N'){
            d[i]=4;
            cin>>l;
            g[i].push_back(l);
        }else if(s[0]=='I'){
            d[i]=5;
            cin>>v[i];
        }
    }
    dfs(1);
    dfs2(1);
    for(int i=1;i<=n;i++){
        if(d[i]==5){
            if(mark[i])cout<<!v[1];
            else cout<<v[1];
        }
    }
    return 0;
}

发布了445 篇原创文章 · 获赞 37 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/105207740