Codeforces Round #214 (Div. 2)

这场题意都好坑,尤其是A。


C:

题意:选若干水果,至少一个。在sum{b[i]*k}-sum{a[i]}==0时,求最大的sum{a[i]}。


思路:选某个水果对平衡的影响是:b[i]*k-a[i]。dp[balance]表示平衡为balance时,最大的sum{a[i]}。答案在dp[0],平衡有可能负数,整体坐标要右移。


code:

#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;

#define N  200100
#define ALL(x)     x.begin(),x.end()
#define CLR(x,a)   memset(x,a,sizeof(x))
typedef pair<int,int> PI;
typedef long long 	  ll;
const ll INF    = 0x3fffffff;
const int MOD    = 7;
const double EPS = 1e-7;

int a[N],b[N];
int dp[2][N];

void update(int &x,int y)
{
	if(x==-1) x=y;
	x=max(x,y);
}

int main()
{   
	int n,k;
	scanf("%d%d",&n,&k);
	for(int i=0;i<n;i++) scanf("%d",a+i);
	for(int i=0;i<n;i++) scanf("%d",b+i),b[i]*=k;
	for(int i=0;i<n;i++) b[i]-=a[i];
	int pre=0,now=1;
	CLR(dp[pre],-1);
	dp[pre][10000]=0;
	for(int i=0;i<n;i++){
		CLR(dp[now],-1);
		for(int j=109900;j>=100;j--){
			if(dp[pre][j]==-1) continue;
			update(dp[now][j],dp[pre][j]);
			update(dp[now][j+b[i]],dp[pre][j]+a[i]);
		}
		swap(pre,now);
	}
	printf("%d\n",dp[pre][10000]>0?dp[pre][10000]:-1);
	return 0;
}



D:

题意:给一张图,每条边有一个范围。你携带一个整数x,如果x落在这条边的范围内,那么你可以通过这条边。你必须从点1带着x走到点n。选择一条路径使得可选的x数量最多,求这个数量。


思路:答案必然是某条边的左边界与某条边的右边界之间的距离。枚举是哪条边的左边界,然后从右边界大的边开始,一直加入集合,直到1和n是连通的。


code:

#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;

#define N  100010
#define ALL(x)     x.begin(),x.end()
#define CLR(x,a)   memset(x,a,sizeof(x))
typedef long long 	 ll;
typedef pair<ll,int> PI;
const int INF    = 0x3fffffff;
const int MOD    = 100000007;
const double EPS = 1e-7;

struct Edge{
	int x,y,l,r;
	bool operator <(const Edge &t)const{
		return r>t.r;
	}
}e[N];

int par[N];
void init(int n)
{
	for(int i=1;i<=n;i++) par[i]=i; 
}
int find(int x){return x==par[x]?x:par[x]=find(par[x]);}
void merge(int x,int y)
{
	x=find(x), y=find(y);
	if(x==y) return;
	par[x]=y;
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=0;i<m;i++){
		scanf("%d%d%d%d",&e[i].x,&e[i].y,&e[i].l,&e[i].r);
	}
	sort(e,e+m);
	int ans=0;
	for(int i=0;i<m;i++){
		init(n);
		for(int j=0;j<m;j++){
			if(e[j].l>e[i].l) continue;
			if(e[j].r<e[i].l) break;
			merge(e[j].x,e[j].y);
			if(find(1)==find(n)){
				ans=max(ans,e[j].r-e[i].l+1);	
			}
		}
	}
	if(ans) cout<<ans<<endl;
	else puts("Nice work, Dima!");
	return 0;
}


E:

题意:给出音符矩阵,两个音符之间的距离为哈顿距离最后再给出一串长度为s的音符,求相邻音符中的最大距离。


思路:先选两种音符,再枚举任意两行。选择其中一行最左(右)的点,与另一行最右(左)的点。这样复杂度是O(k*k*n*n),事实上这种复杂度也能过。当然可以优化,观察式子i-j+r[i]-l[j](j<=i),可以维护max{-j-l[j]},另一个式子同理。然后复杂度就将为(k*k*n)


code:

#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;

#define N  100010
#define ALL(x)     x.begin(),x.end()
#define CLR(x,a)   memset(x,a,sizeof(x))
typedef long long 	 ll;
typedef pair<ll,int> PI;
const int INF    = 0x3fffffff;
const int MOD    = 100000007;
const double EPS = 1e-7;

vector<int> d[16][2024];
int a[2024][2024],dis[16][16];
int n,m;

void solve(int x,int y)
{
	int L=-INF,R=-INF,ans=0;
	for(int i=0;i<n;i++){
		if(d[y][i].size()){
			L=max(L,-i-d[y][i][0]);
			R=max(R,-i+d[y][i][d[y][i].size()-1]);
		}
		if(L==-INF) continue;
		if(d[x][i].size()){
			ans=max(ans,i+d[x][i][d[x][i].size()-1]+L);
			ans=max(ans,i-d[x][i][0]+R);
		}
	}
	if(x>y) swap(x,y);
	dis[x][y]=max(dis[x][y],ans);
}

int main()
{
	int k,s,x,y;
	scanf("%d%d%d%d",&n,&m,&k,&s);
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			scanf("%d",&a[i][j]);
			d[a[i][j]][i].push_back(j);
		}
	}
	for(int i=1;i<=k;i++)
		for(int j=1;j<=k;j++)
				solve(i,j);
	int ans=0;
	scanf("%d",&x);
	for(int i=1;i<s;i++){
		scanf("%d",&y);
		ans=max(ans,dis[min(x,y)][max(x,y)]);
		x=y;
	}
	printf("%d\n",ans);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值