题解:Codeforces#499 Div.1

Codeforces#499 Div.1

其实总的来说,这次 Div.1 D i v .1 前四题挺水的,认真思考下都会做,代码量也不大,覆盖面广,难度适中,码量适中,解法自然,你可以利用这些题目,为自己的 Rating R a t i n g 上升提供一个强有力的援助。

A.Fly

题目大意

你有 n n 个点,初始重量为m(不包括燃料重),你需要从1号点开始依次走过所有点至 n n 号点,最后从n号点回到1好点,因此是从1号点上升,然后在2号点下降,再从2号点上升,在3号点下降…在n号点上升,在1号点下降,第 i i 个点有上升值a[i] 和降落值 b[i] b [ i ] ,燃料减去(m+当前燃料重) ÷ ÷ a[i] a [ i ] (上升时,下降时为 b[i] b [ i ] ) ,求最小携带燃料重

数据范围

n1000 n ≤ 1000 , m1000 m ≤ 1000 , a[i],b[i]1000 a [ i ] , b [ i ] ≤ 1000 , 最小携带燃料重 1e9 1 e 9

Sol

一开始想到二分,但发现可以不用带 log l o g

然后发现可以倒着做,假设最后一次回到1时燃料全用完就可以了

Code

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int _=1005;
inline int read()
{
    char ch='!';int z=1,num=0;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')z=-1,ch=getchar();
    while(ch<='9'&&ch>='0')num=(num<<3)+(num<<1)+ch-'0',ch=getchar();
    return z*num;
}
int n,m,a[_],b[_];
double k;
int main()
{
    n=read();scanf("%lf",&m);
    for(int i=1;i<=n;++i)a[i]=read();
    for(int i=1;i<=n;++i)b[i]=read();b[n+1]=b[1];
    bool flag=0;
    for(int i=n;i;--i)
    {
        if(b[i+1]==1){flag=1;puts("-1");break;}
        k+=1.0*(m+k)/(b[i+1]-1);
        if(a[i]==1){flag=1;puts("-1");break;}
        k+=1.0*(m+k)/(a[i]-1);
    }
    if(!flag)printf("%.6lf\n",k);
    return 0;
}

B.Rocket

题目大意

有个数 x x ,可以进行询问一个值y,会返回一个“-1,0, 1”中的值,-1表示x y y 小,0表示x刚好等于 y y ,此时你需要立刻结束程序,1表示x y y 大。但是机器会出问题,可能会返回一个与原本值相反的值,例如-1返回1,1返回-1(但0仍然返回0)。你有不超过60次询问机会,请你打印出所有询问。

数据范围

n30 , m1e9 m ≤ 1 e 9

Sol

观察到n最大只有30,不就是不停询问1得到序列p,然后用 230 2 30 二分 x x 就好了

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
const int _=35;
inline int read()
{
    char ch='!';int z=1,num=0;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')z=-1,ch=getchar();
    while(ch<='9'&&ch>='0')num=(num<<3)+(num<<1)+ch-'0',ch=getchar();
    return z*num;
}
int m,n,a[_];
int main()
{
    m=read(),n=read();
    for(int i=1;i<=n;++i)
    {
        puts("1");fflush(stdout);
        a[i]=read();
        if(!a[i]){puts("1");exit(0);}
    }
    int l=2,r=m;int now=0;
    while(l<=r)
    {
        int mid=(l+r)>>1;now++;
        if(now==n+1)now=1;
        printf("%d\n",mid);fflush(stdout);
        int x=read();
        if(!x){exit(0);}
        if((x==-1&&a[now]==-1)||(x==1&&a[now]==1))l=mid+1;
        else r=mid-1;
    }
    return 0;
}

C.Border

题目大意

你有n个数,每个数都可以使用无限次,你可以将某些数相加得到一个新数(也可以自己加自己),请记录这些数字(包括构造的新数)在mod k意义下有多少种

数据范围

n100000 n ≤ 100000 , k100000 k ≤ 100000 , a[i]1e9 a [ i ] ≤ 1 e 9 ,所有数字均已十进制给出

Sol

这个其实博主也不会理性证明,但是感性想想还是很好的。如果一个数 X X 在modK意义下的和其他数的GCD为 d d ,那么在K范围内的 d d 的倍数也一定成立(因为任意搭配,个数无限),然后统计就好啦

Code

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int _=100005;
inline int read()
{
    char ch='!';int z=1,num=0;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')z=-1,ch=getchar();
    while(ch<='9'&&ch>='0')num=(num<<3)+(num<<1)+ch-'0',ch=getchar();
    return z*num;
}
int n,k,a[_],p[_];
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int main()
{
    n=read(),k=read();
    for(int i=1;i<=n;++i)a[i]=read()%k;
    for(int i=1;i<=n;++i)a[i]=gcd(a[i],k);
    int d=0;
    for(int i=1;i<=n;++i)d=gcd(d,a[i]);
    for(int i=0;i<k;i+=d)p[++p[0]]=i;
    printf("%d\n",p[0]);
    for(int i=1;i<=p[0];++i)printf("%d ",p[i]);
    puts("");
    return 0;
}

D.Mars rover

题目大意

你有一棵树,树上的叶子节点权值由输入决定,除叶子节点外所有点具有一个运算操作,是(与,或,异或,取反)中一个,该节点值由其叶子节点进行该运算操作决定。

询问:对于所有叶子节点,若将该节点的值取反,是否会对根节点(1号点产生影响),是为1否为0。

数据范围

n1e6 , 叶节点值均 0,1 ∈ 0 , 1

Sol

预处理出树上各个节点的值,然后dp一下, f[i] f [ i ] 表示将该节点取反后是否会影响到根节点的值。

那么 f[u] f [ u ] 显然受 f[fa[u]] f [ f a [ u ] ] 影响,只有在 f[fa[u]]=1 f [ f a [ u ] ] = 1 的情况下, f[u] f [ u ] 才有可能能取到1,然后其实代码挺容易打的

Code

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int _=1001000;
int n,c[_],s[_][2],f[_];
char op[20];
void Pre(int u)
{
    for(int i=0;i<2;++i)
    {
        int v=s[u][i];
        if(!v)continue;
        Pre(v);
    }
    if(c[u]==1)f[u]=f[s[u][0]]&f[s[u][1]];
    if(c[u]==2)f[u]=f[s[u][0]]|f[s[u][1]];
    if(c[u]==3)f[u]=f[s[u][0]]^f[s[u][1]];
    if(c[u]==4)f[u]=f[s[u][0]]^1;
}
bool dp[_];
void dfs(int u,int fa)
{
    if(dp[fa]&&fa)
    {
        int k=s[fa][0]==u?1:0,t=f[u]?0:1;
        if(c[fa]==1)dp[u]=f[s[fa][k]]&t,dp[u]^=f[fa];
        if(c[fa]==2)dp[u]=f[s[fa][k]]|t,dp[u]^=f[fa];
        if(c[fa]==3)dp[u]=f[s[fa][k]]^t,dp[u]^=f[fa];
        if(c[fa]==4)dp[u]=dp[fa];
    }
    for(int i=0;i<2;++i)
    {
        int v=s[u][i];
        if(!v)continue;
        dfs(v,u);
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
        scanf("%s",op);
        if(op[0]=='I')scanf("%d",&f[i]);
        else
        {
            if(op[0]=='A')scanf("%d%d",&s[i][0],&s[i][1]),c[i]=1;
            if(op[0]=='O')scanf("%d%d",&s[i][0],&s[i][1]),c[i]=2;
            if(op[0]=='X')scanf("%d%d",&s[i][0],&s[i][1]),c[i]=3;
            if(op[0]=='N')scanf("%d",&s[i][0]),c[i]=4;
        }
    }
    dp[0]=dp[1]=1;Pre(1);dfs(1,0);
    for(int i=1;i<=n;++i)
    {
        if(c[i])continue;
        printf("%d",dp[i]?f[1]^1:f[1]);
    }puts("");
    return 0;
}

E.Store

题目大意

在一个三维空间中,存在一个长方体,但并不知道它的具体位置,但有 n n 个点在长方体内,m个点不在长方体内,先判断是否合法,若合法再给出k组询问,每次询问某个点是否在长方体内(回答在,不在,或不确定)

数据范围

XMax,YMAX,ZMAX,n,m,k1e5 X M a x , Y M A X , Z M A X , n , m , k ≤ 1 e 5

Sol

KD-Tree暂时不会,会了再回来更

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值