Noip模拟题解题报告

Pro

题目链接

Sco

预计得分: 100 + 100 + 30 = 230 100 + 100 + 30 = 230 100+100+30=230

实际得分: 100 + 100 + 30 = 230 100 + 100 + 30 = 230 100+100+30=230

Sol##

业务办理

贪心题。

按照最长等待时间升序排序,然后从头到尾模拟着跑一边就好了。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

struct Per {
	long long t , d;
};
Per c[100005];
long long n , ans , tim = 0;
inline long long mymax(long long a , long long b) { return a>b?a:b; }
inline long long exc(long long x) { return x<0?0:x; }
bool cmp(Per x , Per y) {
	if(x.d == y.d)
		return x.t < y.t;
	return x.d < y.d;
}

int main() {
	freopen("transact.in","r",stdin);
	freopen("transact.out","w",stdout); 
	scanf("%lld",&n);
	for(int i=1; i<=n; i++)
		scanf("%lld",&c[i].t);
	for(int i=1; i<=n; i++)
		scanf("%lld",&c[i].d);
	sort(c+1 , c+n+1 , cmp);
	for(int i=1; i<=n; i++) {
		tim += c[i].t;
		ans = mymax(ans , exc(tim - c[i].d));
	}
	printf("%lld",ans);
	return 0;
}

传球接力

第一次直接打了50分就去看第三题了,打完第三题的暴力又回来想出正解。

首先知道,n个点n条边,一定存在环。

我们深搜求出每一个环来……

(很久之前的模拟题,突然忘了当时怎么想的了……)

反正就是拓扑胡乱搞搞就能A。

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;

const int L = 500005;
struct Node {
	int to;
	long long len;
};
Node e[L];
queue<int>q;
vector<int>d;
int n , s;
long long sum , pre[L] , ans , flag , cir[L] , top , is , vis[L] , ind[L] , dit[L];
inline long long mymax(long long a , long long b) { return a>b?a:b; }

void dfs1(int u) {
	int v = e[u].to;
	if(vis[v]==flag) {
		s = v;
		is = 1;
		return ;
	}
	if(vis[v]) {
		is = 0;
		return ;		
	}
	vis[v] = flag;
	dfs1(v);
}

void dfs2(int u) {
	cir[++top] = u;
	sum += e[u].len;
	pre[e[u].to] = e[u].len;
	if(e[u].to == s)
		return;
	dfs2(e[u].to);
}

void topo() {
	for(int i=1; i<=n; i++)
		if(!pre[i]&&!ind[i])
			q.push(i);
	while(!q.empty()) {
		int u , v;
		u = q.front();
		q.pop();
		v = e[u].to;
		if(!pre[v])
			dit[v] = mymax(dit[v] , dit[u]+e[u].len);
		else
			d.push_back(u);
		ind[v]--;
		if(!ind[v])
			q.push(v);
	}
}

int main() {
	freopen("pass.in","r",stdin);
	freopen("pass.out","w",stdout);
	scanf("%d",&n);
	for(int i=1; i<=n; i++) {
		int x;
		long long y;
		scanf("%d%lld",&x,&y);
		e[i].to = x;
		e[i].len = y;
		ind[x]++;
	}
	for(int i=1; i<=n; i++) {
		if(vis[i])
			continue;
		sum = 0; is = 0; flag++; top = 0;
		dfs1(i);
		if(is) {
			dfs2(s);
			for(int i=1; i<=top; i++) {
				pre[cir[i]] = sum - pre[cir[i]];
				ans = mymax(ans , pre[cir[i]]);	
			}	
		}	
	}
	topo();
	for(int i=0; i<d.size(); i++)
		ans = mymax(ans , e[d[i]].len+pre[e[d[i]].to]+dit[d[i]]);
	printf("%lld",ans);
	return 0;
}

捡金币

貌似时间限制是3s……

如果1s的话 直接dp可以过80 还是很不错的

当时打的是30分的暴力分,然后推了一会dp,发现打错了,于是得了30的暴力分。

方程很好写,也很好时间,不多说了。

#include<iostream>
#include<cstdio>
using namespace std;

int n , C , W , T;
int dp[105][30][30][155] , ans , map[105][30][30];
inline long long mymax(long long a , long long b) { return a>b?a:b; }

int main() {
	freopen("coin.in","r",stdin);
	freopen("coin.out","w",stdout);
	scanf("%d%d%d%d",&n,&C,&W,&T);
	for(int i=1; i<=T; i++)
		for(int j=1; j<=n; j++)
			for(int k=1; k<=n; k++)
				scanf("%d",&map[i][j][k]);
	for(int i=1; i<=T; i++) {
		for(int x=1; x<=n; x++) {
			for(int y=1; y<=n; y++) {
				for(int k=0; k<=W; k++) {
					dp[i][x][y][k] = mymax(dp[i][x][y][k] , dp[i-1][x][y][k]+map[i][x][y]);
					dp[i][x][y][k] = mymax(dp[i][x][y][k] , dp[i-1][x+1][y][k]+map[i][x][y]);
					dp[i][x][y][k] = mymax(dp[i][x][y][k] , dp[i-1][x-1][y][k]+map[i][x][y]);
					dp[i][x][y][k] = mymax(dp[i][x][y][k] , dp[i-1][x][y+1][k]+map[i][x][y]);
					dp[i][x][y][k] = mymax(dp[i][x][y][k] , dp[i-1][x][y-1][k]+map[i][x][y]);
					for(int m=1; m<=C; m++) {
						if(k-m<0)
							break;
						int mov = 2*m;
						if(x-mov>=1)
							dp[i][x][y][k] = mymax(dp[i][x][y][k] , dp[i-1][x-mov][y][k-m]+map[i][x][y]);
						if(x+mov<=n)
							dp[i][x][y][k] = mymax(dp[i][x][y][k] , dp[i-1][x+mov][y][k-m]+map[i][x][y]);
						if(y-mov>=1)
							dp[i][x][y][k] = mymax(dp[i][x][y][k] , dp[i-1][x][y-mov][k-m]+map[i][x][y]);
						if(y+mov<=n)
							dp[i][x][y][k] = mymax(dp[i][x][y][k] , dp[i-1][x][y+mov][k-m]+map[i][x][y]);
						ans = mymax(ans , dp[i][x][y][k]);
					}
				}
			}
		}
	}
	printf("%d",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值