Codeforces Round #219 (Div. 1)

这场一开始A题用set乱贪一发就交了,然后WA第六组。。。。然后二分乱搞过的。B题真的是想晕了,4秒的时限就是骗人的嘛。。。最后用1600*1600复杂度过的。。。思维不行,还需要好好练习。。。


A:

题意:

      把一个袋鼠装进另一个袋鼠。每个袋鼠只能装一个袋鼠且必须体积小于等于自己的一半。不能装 装了袋鼠的袋鼠。求最少剩       多少只袋鼠。


思路:二分有多少只袋鼠被装。


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

int n;
int a[N];

bool check(int x)
{
	for(int i=0;i<x;i++){
		if(2*a[i]>a[n-x+i]) return false;
	}
	return true;
}

int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;i++)
		scanf("%d",&a[i]);
	sort(a,a+n);
	int l=0,r=n/2+1;

	while(l<r){
		int mid=(l+r)>>1;
		if(check(mid)) l=mid+1;
		else r=mid;

	}
	printf("%d\n",n-r+1);
    return 0;
}



B:


题意:求矩阵里有多少个子矩阵全包含零。


思路:dp[x0][y0][x1][y1] 表示矩阵{x0<=x<=x1,y0<=y<=y1}有多少个包含1的矩阵,tot[x0][y0][x1][y1]则表示有多少个子矩阵,对减下就是答案,递推的方法看代码,类似容斥。


比赛的时候没有去递推tot,一直以为是算一下组合数就是了,然后狂卡样例。。。。真是弱。。代码略翔,递推太长了。


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

int n,m;
int sum[64][64][64][64];
int tot[64][64][64][64];

int main()
{
	int x0,x1,y0,y1;
	scanf("%d%d",&n,&m);
	int Q;
	scanf("%d",&Q);

	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			scanf("%1d",&sum[i][j][i][j]);
			tot[i][j][i][j]=1;
		}

	for(int h=1;h<=n;h++){
		for(int w=1;w<=m;w++){
			if(h==1 && w==1) continue;
			for(int i=1;i<=n;i++){
				for(int j=1;j<=m;j++){
					int k=i+h-1,q=j+w-1;
					if(k>n || q>m) break;
					sum[i][j][k][q]+=sum[i+1][j][k][q]+sum[i][j+1][k][q]+sum[i][j][k-1][q]
							+sum[i][j][k][q-1];
					sum[i][j][k][q]-=sum[i+1][j+1][k][q]+sum[i+1][j][k-1][q]+sum[i+1][j][k][q-1]
							+sum[i][j+1][k-1][q]+sum[i][j+1][k][q-1]+sum[i][j][k-1][q-1];
					sum[i][j][k][q]+=sum[i+1][j+1][k-1][q]+sum[i+1][j+1][k][q-1]
							+sum[i+1][j][k-1][q-1]+sum[i][j+1][k-1][q-1];
					sum[i][j][k][q]-=sum[i+1][j+1][k-1][q-1];
					sum[i][j][k][q]+=(sum[i][j][k][q]>0);

					tot[i][j][k][q]+=tot[i+1][j][k][q]+tot[i][j+1][k][q]+tot[i][j][k-1][q]
							+tot[i][j][k][q-1];
					tot[i][j][k][q]-=tot[i+1][j+1][k][q]+tot[i+1][j][k-1][q]+tot[i+1][j][k][q-1]
							+tot[i][j+1][k-1][q]+tot[i][j+1][k][q-1]+tot[i][j][k-1][q-1];
					tot[i][j][k][q]+=tot[i+1][j+1][k-1][q]+tot[i+1][j+1][k][q-1]
							+tot[i+1][j][k-1][q-1]+tot[i][j+1][k-1][q-1];
					tot[i][j][k][q]-=tot[i+1][j+1][k-1][q-1];
					tot[i][j][k][q]++;
				}
			}
		}
	}

	while(Q--){
		scanf("%d%d%d%d",&x0,&y0,&x1,&y1);
		printf("%d\n",tot[x0][y0][x1][y1]-sum[x0][y0][x1][y1]);
	}

    return 0;
}


C:

题意:

        有n个看台排成一条直线。现在要放m次烟花。每次放烟花,你会获得b-|a-x|的收益,a表示烟花在哪个看台放,x是你所在的位置。每单位时间你最多能移动距离d,给出了每组烟花燃放的时间,求最大收益。


思路:

        dp[i][j] 表示燃放第i组烟花,此时人在第j个看台时候的最大收益。

        用dis表示从i-1到i最多能移动的距离,那么转移就是dp[i][j]=max{dp[i-1][k] | abs(j-k)<=dis }。用单调队列优化下,就能过了。


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

deque<int> que;
ll dp[2][N];

int main()
{
	int n,m,d,pret=0,pre=1,now=0;
	int a,b,t;
	scanf("%d%d%d",&n,&m,&d);
	for(int i=0;i<m;i++){
		scanf("%d%d%d",&a,&b,&t);
		ll dis=1ll*d*(t-pret);
		pret=t;
		que.clear();
		for(int j=1;j<=n;j++){
			while(!que.empty() && dp[pre][j]>dp[pre][que.back()]) que.pop_back();
			que.push_back(j);
			while(dis<abs(que.front()-j)) que.pop_front();
			dp[now][j]=dp[pre][que.front()];
		}
		que.clear();
		for(int j=n;j>=1;j--){
			while(!que.empty() && dp[pre][j]>dp[pre][que.back()]) que.pop_back();
			que.push_back(j);
			while(dis<abs(que.front()-j)) que.pop_front();
			dp[now][j]=max(dp[now][j],dp[pre][que.front()]);
		}
		for(int j=1;j<=n;j++) dp[now][j]+=b-abs(j-a);
		swap(pre,now);
	}
	printf("%I64d\n",*max_element(dp[pre]+1,dp[pre]+n+1));
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值