您的位置:首页 > 其它

codeforces 283,284(Round #174)题解

2013-03-22 20:18 274 查看
2A:暴力即可,有数学方法,答案即为phi(phi(p)),具体证明详见
http://jijiwaiwai163.blog.163.com/blog/static/186296211201261133849397/
2B:记录'I'的个数a,'A'的个数b,a=0显然答案就是b,a=1答案显然只能为1,a>=2答案显然为0。

2C(1A):由于1~i均加一个值,完全没必要1~i都记录,只需记录每次加的最后一个数加了多少即可,每次弹出的时候,把最后一个数累加的加到前面一个数即可,注意,弹出时一定要清零,否则以后再加的时候就错了(thx谷神T_T)

上代码:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int N=200005;
int a
,w
;
int main()
{
int i,t,n;
scanf("%d",&n);
double sum=0;
int l=1;
int x,y;
for(i=0;i<n;++i)
{
scanf("%d",&t);
if(t==1)
{
scanf("%d%d",&x,&y);
a[x]=a[x]+y;
sum+=(double)x*y;
}
if(t==2)
{
scanf("%d",&x);
sum+=(double)x;
w[++l]=x;
}
if(t==3)
{
sum-=(double)(w[l]+a[l]);
a[l-1]+=a[l];
w[l]=a[l]=0;
l--;
}
printf("%.6lf\n",sum/(double)l);
}
return 0;
}


2D(1B):首先看数据范围,显然不能暴力。然后又会想到每个数列主要区别在于a1加的值,其他区别在于第二步从第几个数计算。所以我们只需记忆化搜索出从a[2],到a
开始计算出的每个y的值,再分别加上i即可。

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=200005;
int n;
long long a
,y
[2];
bool v
[2];
long long dfs(int x,int t)
{
if(x<=0 || x>n) return 0;
if(x==1) return -1;
if(v[x][t]) return y[x][t];
v[x][t]=true;
y[x][t]=-1;
if(t==1) y[x][t]=dfs(x-a[x],0);
if(t==0) y[x][t]=dfs(x+a[x],1);
if(y[x][t]!=-1) y[x][t]+=a[x];
return y[x][t];
}
int main()
{
int i;
scanf("%d",&n);
for(i=2;i<=n;++i)
scanf("%I64d",&a[i]);
for(i=2;i<=n;++i)  if(!v[i][1]) dfs(i,1);//记忆化搜素,搜索a[2]到a
状态开始计算出的值
for(i=1;i<n;++i)
if(y[i+1][1]==-1) printf("-1\n");
else printf("%I64d\n",y[i+1][1]+i);
return 0;
}
2E(1C):完全背包,比较水,关键在于有物品数量是严格大于其他物品的,这种情况只需把前者价值加上后者即可。

注意这种物品有两种,一种是只限制别人,不被限制,另一种是限制别人同时自己也被限制。搞个ind[]数组存储,

先存第一类,再存第二类,这样第一类价值可以累加到第二类上,第二类价值可以加到只被限制的物品上,完全背包即可

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=305,MOD=1000000007;
int w
,p
,vis
,dep
,ind
,f[100005];
int main()
{
int i,j,n,q,t;
int x,y;
scanf("%d%d%d",&n,&q,&t);
for(i=1;i<=n;++i) scanf("%d",&w[i]);
for(i=1;i<=q;++i)
{
scanf("%d%d",&x,&y);
p[x]=y;
vis[x]=1;
dep[y]++;
}
int tot=0;
for(i=1;i<=n;++i) if(vis[i] && !dep[i]) ind[++tot]=i;
for(i=1;i<=tot;i++)
{
int now=ind[i];
if(vis[p[now]] && dep[p[now]]==1) ind[++tot] = p[now];
}
if(tot!=q) printf("0");
else
{
for(i=1;i<=tot;++i)
{
int now=ind[i];
int af=p[now];
w[af]+=w[now];
t=t-w[now];
if(t<0) {printf("0");return 0;}
}
f[0]=1;
for(i=1;i<=n;++i)
{
for(j=w[i];j<=t;++j)
{
f[j]=(f[j]+f[j-w[i]])%MOD;
}
}
printf("%d",f[t]);
}
return 0;
}


1D:不错的题,f
表示满足条件的数有多少,ans=min(n-f
)。对于j<i如果a[i]为奇数且a[j]%a[i]=0,显然满足;

如果a[i]为偶数,a[j]%a[i]=a[i]/2,也满足(想一想,为什么)。如果a[i]为偶数a[i-2],a[i-1],a[i]若都想成立,

a[i-1]需为a[i]/2(我自己YY感觉的T_T,大致推了一下)。

#include<cstdio>//dp,记录满足条件最多多少个数即可
#include<iostream>
#include<algorithm>
using namespace std;
const int N=5005;
long long a
,f
;
int main()
{
int i,j,n;
scanf("%d",&n);
for(i=1;i<=n;++i)  scanf("%I64d",&a[i]);
for(i=1;i<=n;++i)
{
long long x=a[i];
f[i]=1;
for(j=i-1;j>=1;--j)
{
if((x&1 && a[j]%x==0)|| (!(x&1) && a[j]%x==x/2)) f[i]=max(f[i],f[j]+1);
if(!(x&1)) x=x>>1;
}
}
long long ans=1000000;
for(i=1;i<=n;++i)
ans=min(ans,n-f[i]);
printf("%I64d",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: