Codeforces Round #174 (Div. 1)

题目:http://www.codeforces.com/contest/283

A:对3个操作分别维护平均值ans。

操作1:更新数字总和,数字个数不变,更新ans,在cnt数组上打上标记来表示前ai个数的值要增加x

操作2:数字个数加1,数字总和加上新插入的数,更新ans

操作3:通过cnt数组更新最后一个数字的值,cnt相应位置上的标记往前移, 数字总和减去最后一个数字的值,数字个数减1


#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<math.h>
#include<string>
#include<map>
#include<set>
#include<iostream>
using namespace std;
typedef long long ll;
const int inf=1<<29;

#define N 200010
int a[N],cnt[N];
int main()
{
	int n,ch,x,y;
	scanf("%d",&n);
	int kk=1;
	a[1]=0;
	double ans=0;
	for(int i=0;i<n;i++){
		scanf("%d",&ch);
		if(ch==1){
			scanf("%d%d",&y,&x);
			y=min(y,kk);
			cnt[y]+=x;
			ans+=y*x*1.0/kk;
		}else if(ch==2){
			scanf("%d",&x);
			ans=(ans*kk+x)/(kk+1);
			a[++kk]=x;
		}else{
			if(kk<2) continue;
			ans=(ans*kk-cnt[kk]-a[kk])/(kk-1);
			cnt[kk-1]+=cnt[kk];
			cnt[kk]=0;
			kk--;
		}
		printf("%.10lf\n",ans);
	}
}


B:设dp[i][0]表示从a[i]开始步骤2到结束y所增加的值,设dp[i][1]表示从a[i]开始步骤3到结束y所增加的值,记忆化dfs求出所有的dp[i][j]。如果a[1]=i,也就是说从a[1]开始步骤2到a[i+1]点进行步骤3,那么答案就是dp[i+1][1]+i


#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<math.h>
#include<string>
#include<map>
#include<set>
#include<iostream>
using namespace std;
typedef long long ll;
const int inf=1<<29;

#define N 200010

int vis[N][2];
ll dp[N][2];
int n,a[N];
ll dfs(int x,int k)
{
	if(x<=0||x>n) return 0;
	if(x==1) return -1;
	if(vis[x][k]) return dp[x][k];
	vis[x][k]=1;
	ll ans=a[x];
	int y;
	if(k) y=x-a[x];
	else y=x+a[x];
	ll t=dfs(y,k^1);
	if(t==-1) ans=-1;
	else ans+=t;
	return dp[x][k]=ans;
}
int main()
{
	scanf("%d",&n);
	for(int i=2;i<=n;i++)
		scanf("%d",&a[i]);
	memset(dp,-1,sizeof(dp));
	for(int i=2;i<=n;i++){
		if(!vis[i][0]){
			dfs(i,0);
		}
		if (!vis[i][1]) {
			dfs(i, 1);
		}
	}
	for(int i=1;i<=n-1;i++){
		if(dp[i+1][1]==-1)
			printf("%d\n",-1);
		else printf("%I64d\n",dp[i+1][1]+i);
	}
}

C:这题其实就是一个有附加条件的背包。考虑这样一个背包问题:n件物品,背包容量为t,要求第i+1件物品拿的比第i件物品多。将物品进行组合,第i件物品到第n件的组合作为第i件物品,这样原问题的要求就转换成了除第1件外的其他物品至少拿一件,这个额外的条件在dp过程中就很容易处理了。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<math.h>
#include<string>
#include<map>
#include<set>
#include<iostream>
using namespace std;
typedef long long ll;
const int inf=1<<29;

#define N 100010
const int mod=1000000007;

int a[310];
vector<int> e[310];
int fa[310],next[310];
int val[310][310];

int dp[N];
int main()
{
	int n,Q,T,x,y;
	scanf("%d%d%d",&n,&Q,&T);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(int i=0;i<Q;i++){
		scanf("%d%d",&x,&y);
		fa[y]=x;next[x]=y;
	}
	int kk=0,cnt=0;
	for(int i=1;i<=n;i++){
		if(next[i]==0){
			int t=i;
			while(t!=0){
				e[kk].push_back(t);
				cnt++;
				t=fa[t];
				if(t==i) break;
			}
			kk++;
		}
	}
	if(cnt<n){
		printf("0\n");
		return 0;
	}
	for(int i=0;i<kk;i++){
		int t=e[i].size()-1;
		val[i][t]=a[e[i][t]];
		for(int j=t-1;j>=0;j--){
			val[i][j]=a[e[i][j]]+val[i][j+1];
		}
	}
	dp[0]=1;
	for(int i=0;i<kk;i++){
		int t=e[i].size()-1;
		for(int j=0;j<=t;j++){
			int v=val[i][j];
			if(j==0){
				for(int k=v;k<=T;k++){
					dp[k]+=dp[k-v];
					dp[k]%=mod;
				}
			}else{
				for(int k=T;k>=v;k--)
					dp[k]=dp[k-v];
				for(int k=0;k<min(v,T+1);k++) dp[k]=0;
				for(int k=v;k<=T;k++){
					dp[k]+=dp[k-v];
					dp[k]%=mod;
				}
			}
		}
	}
	printf("%d\n",dp[T]);
}


D:设dp[i]表示以a[i]为结尾的cool序列最多能不改变几个数字,如果a[i]为奇数,那么如果a[j]%a[i]==0(1<=j<i),dp[i]=max(dp[j]+1,dp[i]);如果a[i]为偶数,那么满足a[i-1]%a[i]==a[i]/2则dp[i-1]可以转移到dp[i] ,同理如果a[i-1]是偶数,dp[i-2]转移到dp[i-1]也是一样。也就是说dp[j]可以转移到dp[i]要满足a[j]%(a[i]/2^(i-j))==(a[i]/2^(i-j))/2(如果(a[i]/2^(i-j))一直是偶数)

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<math.h>
#include<string>
#include<map>
#include<set>
#include<iostream>
using namespace std;
typedef long long ll;
const int inf=1<<29;

ll a[5010];
int dp[5010];
int main()
{
	int n,ans=0;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%I64d",&a[i]);
		dp[i]=1;
		ll y=a[i];
		for(int j=i-1;j>=1;j--){
			if(y%2&&a[j]%y==0)
				dp[i]=max(dp[j]+1,dp[i]);
			if(y%2==0&&a[j]%y==y/2)
				dp[i]=max(dp[j]+1,dp[i]);
			y=y&1?y:y>>1;
		}
		ans=max(ans,dp[i]);
	}
	printf("%d\n",n-ans);
}



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值