Codeforces#499 Div.1
其实总的来说,这次 Div.1 D i v .1 前四题挺水的,认真思考下都会做,代码量也不大,覆盖面广,难度适中,码量适中,解法自然,你可以利用这些题目,为自己的 Rating R a t i n g 上升提供一个强有力的援助。
A.Fly
题目大意
你有 n n 个点,初始重量为(不包括燃料重),你需要从1号点开始依次走过所有点至 n n 号点,最后从号点回到1好点,因此是从1号点上升,然后在2号点下降,再从2号点上升,在3号点下降…在n号点上升,在1号点下降,第 i i 个点有上升值 和降落值 b[i] b [ i ] ,燃料减去(m+当前燃料重) ÷ ÷ a[i] a [ i ] (上升时,下降时为 b[i] b [ i ] ) ,求最小携带燃料重
数据范围
n≤1000 n ≤ 1000 , m≤1000 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表示比 y y 小,0表示刚好等于 y y ,此时你需要立刻结束程序,1表示比 y y 大。但是机器会出问题,可能会返回一个与原本值相反的值,例如-1返回1,1返回-1(但0仍然返回0)。你有不超过60次询问机会,请你打印出所有询问。
数据范围
, m≤1e9 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
题目大意
你有个数,每个数都可以使用无限次,你可以将某些数相加得到一个新数(也可以自己加自己),请记录这些数字(包括构造的新数)在mod k意义下有多少种
数据范围
n≤100000 n ≤ 100000 , k≤100000 k ≤ 100000 , a[i]≤1e9 a [ i ] ≤ 1 e 9 ,所有数字均已十进制给出
Sol
这个其实博主也不会理性证明,但是感性想想还是很好的。如果一个数 X X 在mod意义下的和其他数的GCD为 d d ,那么在范围内的 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。
数据范围
, 叶节点值均 ∈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 个点在长方体内,个点不在长方体内,先判断是否合法,若合法再给出k组询问,每次询问某个点是否在长方体内(回答在,不在,或不确定)
数据范围
XMax,YMAX,ZMAX,n,m,k≤1e5 X M a x , Y M A X , Z M A X , n , m , k ≤ 1 e 5
Sol
KD-Tree暂时不会,会了再回来更