[补题] Codeforces Round #499 (Div. 2) 题解

原来一场比赛AK后会变颜色,长见识了
[补题] Codeforces Round #499 (Div. 2) 题解_第1张图片

1011A. Stages 贪心

给出n个字母,从中挑选k个排成一列使得后一个在字母表中至少是前一个的后两位.求这个序列最小的字母值的和,无解输出-1.

简单贪心,注意a的值是1而不是0.

char save[M];
int main(void)
{
    int n=read(),k=read();
    scanf("%s",save);
    sort(save,save+n);
    int ans = 0, now = -2,len = 0;
    for(int i=0;iif(save[i]>now+1)
        {
            now = save[i];
            ans += save[i]-'a'+1;
            len++;
        }
    }
    printf("%d\n",len1:ans );

    return 0;
}

1011B. Planning The Expedition 暴力

有n(100)个人和m(100)单位食品,每单位食品都有一个种类(有的相同),一个人如果吃了一种食品就再也不能吃其他种类的食品,每人每天需要消耗一单位食品,问这些人最多能坚持几天?

小数据,暴力.

int save[M];
int main(void)
{
    int n=read(),m=read();
    map<int,int> mp;
    for(int i=0;iint ans = 0;
    for(;;ans++)
    {
        int tmp = 0;
        for(auto x:mp)
            tmp+=x.second/(ans+1);
        if(tmpbreak;
    }
    printf("%d\n",ans );
    return 0;
}

这个题满足二分性质.
比赛时WA一次,循环上限写错了.

1011C. Fly 思维

飞船要按顺序飞n(1000)个星球,只有起飞和降落会消耗燃料,每个星球的每个过程都有一个独立的比值k(1<=k<=1000),设当前飞船总重(包括燃料)为M,则这个过程会消耗M/k的燃料.给定所有的k与飞船自重,问在起点最少装多少燃料可以飞完全程.

飞行的顺序是没有影响的,每次相当于总重乘上(k-1)/k,所以只要有一个k为1就无解.
可以证明,飞完全程所需要的燃料是满足二分性质的,但本题可以不用二分来做.
设自重为M,最少需要燃料X,则有

(M+X)(ki1)ki=M ( M + X ) ∗ ∏ ( k i − 1 ) k i = M

解方程即可.

int save[M];
int main(void)
{
    int n = 2 * read(), m = read();
    double A = 1.0;
    while(n--)
    {
        int k = read();
        if(k==1)
        {
            printf("-1\n");
            return 0;
        }
        A *= k;
        A /= k-1;
    }
    printf("%.7f\n",m*A-m );

    return 0;
}

1011D. Rocket 交互题,二分

猜数字游戏,数字范围1e9,最多猜60次,每次给出提示(大/小/正确),但是提示是会出错的,有一个长n(30)位的内置序列,序列为1时出错,为0时正确.

先猜n次1把序列试出来,然后二分解决.

int save[M];
int main(void)
{
    int m=read(),n=read();
    for(int i=0;iprintf("%d\n",1 );
        fflush(stdout);
        save[i] = read();
        if(save[i]==0)
            return 0;
    }
    int l = 2, r = m, cnt = 0;
    while(1)
    {
        int mid = (l+r)>>1;
        printf("%d\n",mid );fflush(stdout);
        int p = read() * save[cnt++ % n];
        if(p==0) return 0;
        else if(p==1) l=mid+1;
        else r = mid-1;
    }

    return 0;
}

得到的一个结论是交互题的读入输出不会与快读冲突,测试时最好手动输入数据.
比赛时因为二分多了两个罚时,复习一下:

int l=1,r=len,ans=-1;
while(l<=r)
{
    int mid = (l+r)>>1;
    if(check(mid,n,m)) ans = mid, l = mid + 1;
    else r = mid - 1;
}

带一个ans之后可以说是非常好写了,注意右移位不要写反!

1011E. Border 结论题

给定n(1e5)个数字(1e9)和一个进制k(1e5),考虑任意多个这些数字的组合,问从0到k-1中哪些数可以成为k进制下这些数字组合的个位数?所有输入输出均使用十进制.

所有的数字模k后与k取gcd,就是最小可以表示的数字间隔.

证明参见

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

int main(void)
{
    int n=read(),k=read(),ans=k;
    while(n--)
        ans = __gcd(ans,read()%k);
    printf("%d\n",k/ans );
    for(int i=0;iprintf("%d ",i );

    return 0;
}

1011F. Mars rover 树,dfs,模拟

给定一个逻辑表达式,包括若干个值确定的01变量,以及NOT,OR,AND,XOR运算符.问对每一个变量取非时逻辑表达式的值,式子以树形给出.

首先计算出表达式的原始值,然后对于这棵树的每个节点,从上到下记录每个节点的值改变时根节点的值是否会改变.注意如果一个节点值改变不影响根节点值,那么它的子节点也不会影响根节点的值,可以省下很多时间.
最后将所有叶子节点的结果输出即可,总复杂度O(n).

/* LittleFall : Hello! */
#include 
using namespace std; typedef long long ll;
inline int read(); inline void write(int x);
const int M = 1000016, MOD = 1000000007;
const char ops[5][5]={"IN","NOT","AND","OR","XOR"};
struct Node
{
    int val;
    int op; //0-in,1-not,2-and,3-or,4-xor
    int son[2];
    int ans;
}save[M];
int getval(int id)
{
    switch(save[id].op)
    {
        case 0: return save[id].val;
        case 1: return save[id].val = !getval(save[id].son[0]);
        case 2: return save[id].val = getval(save[id].son[0]) & getval(save[id].son[1]);
        case 3: return save[id].val = getval(save[id].son[0]) | getval(save[id].son[1]);
        case 4: return save[id].val = getval(save[id].son[0]) ^ getval(save[id].son[1]);
    }
    return 0;
}
void getans(int id)
{
    save[id].ans = 1;
    if(save[id].op==1)
        getans(save[id].son[0]);
    if(save[id].op<2)
        return;
    int son1 = save[id].son[0], son2 = save[id].son[1];
    if(save[id].op==2)
    {
        if(((!save[son1].val) & save[son2].val) != save[id].val)
            getans(son1);
        if(((!save[son2].val) & save[son1].val) != save[id].val)
            getans(son2);
    }
    if(save[id].op==3)
    {
        if(((!save[son1].val) | save[son2].val) != save[id].val)
            getans(son1);
        if(((!save[son2].val) | save[son1].val) != save[id].val)
            getans(son2);
    }
    if(save[id].op==4)
    {
        if(((!save[son1].val) ^ save[son2].val) != save[id].val)
            getans(son1);
        if(((!save[son2].val) ^ save[son1].val) != save[id].val)
            getans(son2);
    }
}
int main(void)
{
    #ifdef _LITTLEFALL_
    freopen("in.txt","r",stdin);
    #endif

    int n=read();
    char tmp[5];
    for(int i=1;i<=n;i++)
    {
        scanf("%s %d",tmp,&save[i].son[0]);
        for(int j=0;j<5;j++)
            if(strcmp(tmp,ops[j])==0)
                save[i].op = j;
        if(save[i].op==0)
            save[i].val = save[i].son[0];
        if(save[i].op>1)
            save[i].son[1] = read();
    }
    int base = getval(1);
    getans(1);
    for(int i=1;i<=n;i++)
        if(save[i].op==0)
            printf("%d",save[i].ans^base );
    return 0;
}


inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline void write(int x)
{
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
} 

你可能感兴趣的:(题解)