【组队补题题】The Seventh Hunan Collegiate Programming Contest Semilive

题目链接:点击打开链接

B 【UVA 12290】 Counting Game


D 【UVA 12292】 Polyomino Decomposer

将给出的图形中的*按照顺序标记,枚举状态,然后判断这个状态是否可行

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int>pii;
int n;
char s[15][15], a[15][15];
int px[25], py[25], num, cnt, xi, yi;
int vis[25][25], dir[4][2]={0,1,1,0,0,-1,-1,0};
int vm[15][15], tot;
char cc[15][15];
queue<pii>q;
struct node
{
	int x, y;
}id[25];
int bfs()
{
	while(!q.empty()) q.pop();
	q.push(make_pair(xi, yi));
	int tmp=1;
	id[tmp-1].x=xi, id[tmp-1].y=yi;
	while(!q.empty())
	{
		pii u = q.front(); q.pop();
		vis[u.first][u.second]=0;
		for(int i=0; i<4; i++)
		{
			int xx=u.first+dir[i][0], yy=u.second+dir[i][1];
			if(xx<0 || xx>=n || yy<0 || yy>=n) continue;
			if(vis[xx][yy]==0) continue;
			if(s[xx][yy]=='.') continue;
			vis[xx][yy]=0, tmp++, q.push(make_pair(xx, yy));
			id[tmp-1].x=xx, id[tmp-1].y=yy;
		}
	}
	return tmp;
}
void check(int xx, int yy)
{
	int len=-1;
	memset(vm, 0, sizeof(vm));
	for(int i=0; i<n; i++){
		for(int j=0; j<n; j++){
			cc[i][j] = a[i][j];
		}
	}
	for(int i=0; i<n; i++){
		for(int j=0; j<n; j++){
			if(s[i][j]=='*' && vm[i][j]==0)
			{
				len++, xx=i, yy=j;
				cc[i][j]='A'+len, vm[i][j]=1;
				for(int k=1; k<num; k++){
					int cx=id[k].x-id[k-1].x;
					int cy=id[k].y-id[k-1].y;
					xx+=cx, yy+=cy;
					if(xx<0 || xx>=n || yy<0 || yy>=n) return;
					if(vm[xx][yy]) return;
					if(s[xx][yy]=='.') return;
					vm[xx][yy]=1, cc[xx][yy]='A'+len;
				}
			}
			
		}
	}
	if(tot==-1 || tot>len+1){//tot:给出的图形可以由tot个基本图形组成,tot越小,字典序越小 
		for(int i=0; i<n; i++){
			for(int j=0; j<n; j++){
				a[i][j] = cc[i][j];
			}
		}
		tot=len+1;
	}
	return;
}
int main()
{
	 while(~scanf("%d", &n))
	 {
	 	if(n==0) break;
	 	xi=yi=-1, cnt=0, tot=-1;
	 	for(int i=0; i<n; i++){
	 		scanf("%s",   s[i]);
	 		for(int j=0; j<n; j++){
	 			if(s[i][j]=='*')
	 			{
	 				a[i][j]='A'+cnt;
	 				px[cnt]=i, py[cnt]=j, cnt++;
	 				if(xi==-1) xi=i, yi=j;
	 			}
	 			else a[i][j]='.';
	 		}
	 		a[i][n]='\0';
	 	} 
	 	for(int i=3; i<(1<<cnt); i+=2) 
	 	{
	 		if(i&1)
	 		{
	 			num=1;
	 			bool flag;
	 			memset(vis, 0, sizeof(vis));
	 			for(int j=1; (1<<j)<=i; j++)
	 			{
	 				int sss = 1<<j;
	 				if(sss&i)
	 				{
	 					vis[px[j]][py[j]]=1;
	 					num++;
	 				}
	 			}
	 			if(cnt%num || cnt==num) continue;
	 			if(num == bfs()) flag=true;//bfs检验这num个点是不是相邻的 
	 			else flag=false;
	 			if(flag) check(xi, yi);//验证给出的图形能不能由这num个点组成 
	 		}
	 	}
	 	for(int i=0; i<n; i++) printf("%s\n", a[i]);
	 	printf("\n");
	 }
	return 0;
}

E 【UVA 12293】Box Game(博弈,找规律)

2 先手必胜

3 先手必败

4 5 6 先手必胜

7 先手必败

8 9 10 11 12 13 14 先手必胜

15 先手必败……

如果面对的情况是:在(n+1)/2 ~n-1中存在先手必败点,这种情况是先手必胜,否则先手必败

分析数据就会发现只有n=2^x-1时先手必败

#include <bits/stdc++.h>
using namespace std; 
int a[30];
void init()
{
	int ans=1;
	for(int i=1; i<30; i++)
	{
		ans*=2;
		a[i]=ans;
	}
}
int main()
{
	int n;
	init();
	while(scanf("%d", &n))
	{
		if(n==0) break;
		int flag=0, ans=1;
		for(int i=1; i<30; i++)
		{
			if(n==a[i]-1) flag=1; 
		}
		if(flag) printf("Bob\n");
		else printf("Alice\n");
	}
	return 0;
}


F 【UVA 12294】 RPG battles

题意:玩游戏,一开始有p(1<=p<=100)能量,有n(1<=n<=1000)个怪,每个怪有六种指标,p1p2t1t2w1w2(1<=p1<p1<=100,1<=t2<t1<=100,0<=w1,w2<=10),打每个怪的时间计算方式是:t1-(p-p1)*(t2-t1)/(p2-p1),当然如果p小于p1,不能打死怪物,输出Impossible,如果p大于p2,时间就是t2。每打死一只怪就能得到奖励技能牌,一类牌w1张,二类牌w2张,一类牌可以将能量值+1,二类牌可以将能量值翻倍,每次可以将奖励牌用完或者不用或用掉部分,怪只能按照顺序一个一个打,一开始手里没有技能牌问最后要是能将所有的怪打死最少需要多少时间?

解题思路:能量值最大都是100,并且能量值越大,杀怪的时间越少,所以我们要在不影响结果的情况下让能量值尽可能的大,那么一类牌遇到一张用掉一张,利用两个优先队列队列枚举每次用的二类牌的张数,输出最少时间。

#include <bits/stdc++.h>
using namespace std;
struct node
{
	int  wi;
	double pi,time;
	friend bool operator < (const node n1, const node n2)
	{
		return n1.time > n2.time;
	} 
}s, e;
int a[10];
void init()
{
	int ans=1;
	a[0]=1;
	for(int i=1; i<=10; i++)
	{
		ans*=2;
		a[i] = ans;
	}
}
priority_queue<node>q[2];
int main()
{
	init();
	int n;
	double m;
	double p, pp, t, tt;
	int w, ww;
	while(~scanf("%d%lf", &n, &m))
	{
		if(n==0 && m==0) break;
		while(!q[0].empty()) q[0].pop();
		while(!q[1].empty()) q[1].pop();
		scanf("%lf%lf%lf%lf%d%d", &p, &pp, &t, &tt, &w, &ww);
		int f=1, ff=0, flag=0;
		if(m<p) flag=1;
		else{
			s.pi=m, s.wi=ww;
			if(s.pi>pp) s.time=tt;
			else s.time=t-(t-tt)*(s.pi-p)/(pp-p);
			if(w) s.pi+=w;
			q[0].push(s);
		}
		for(int i=1; i<n; i++)
		{
			scanf("%lf%lf%lf%lf%d%d", &p, &pp, &t, &tt, &w, &ww);
			if(flag) continue; 
			int vv=0;
			while(!q[ff].empty())
			{
				s=q[ff].top(); q[ff].pop();
				for(int i=0; i<=s.wi; i++)
				{
					e.pi=s.pi*a[i];
					if(e.pi<p) continue;
					else if(e.pi>pp) e.time=s.time+tt;
					else e.time=s.time+t-(t-tt)*(e.pi-p)/(pp-p);
					e.wi=s.wi-i+ww;
					if(w) e.pi+=w;
					q[f].push(e);
					vv=1;
					if(e.pi-w>=100) break;
				}
			}
			if(vv==0) flag=1;
			swap(ff, f);
		}
		if(flag) printf("Impossible\n");
		else printf("%.2lf\n", q[ff].top().time);
	}
	return 0;
}


G 【UVA 12295】Optimal Symmetric Paths(建图&&最短路&&搜索)

题意:一个n*n的棋盘,每格棋盘上都有一个数字,求从(1,1)开始走到(n,n)路径的条数(可以往上下左右四个方向走),路径满足以下条件:1、关于对角线对称 2、路径上的所有点的和最小

解题思路:将对角线下方的方格里的值加到对角线上方,从(0, 0)开始找到一条通向对角线的路,那么这条路上的和就是从(0, 0)走到(n-1, n-1),并且路线关于对角线对称。点(i, j)记为第i*n+j个点。建图,将相邻两点连通,用最短路算法求出从起始点到对角线上方的点的最短距离,同时用vector容器fa[v]来记录到能到点v的点,从对角线dis最小的点开始反向搜路径条数。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int mod=1e9+9;
const int N=150;
const int maxm=3e5;
int n, a[N][N];
int head[maxm], dir[4][2]={0,1,1,0,0,-1,-1,0};
queue<int>q;
vector<int>fa[maxm];
int to[maxm], w[maxm], nxt[maxm];
int tot, dis[maxm];
ll dp[maxm];
bool vis[maxm];
void init()
{
	memset(head, -1, sizeof(head));
	tot=0;
	while(!q.empty()) q.pop();
	memset(dis, 0x3f3f3f3f, sizeof(dis));
	memset(vis, 0, sizeof(vis));
	for(int i=0; i<maxm; i++) fa[i].clear();
	memset(dp, 0, sizeof(dp));
}

void input()
{
	for(int i=0; i<n; i++){
		for(int j=0; j<n; j++) scanf("%d", &a[i][j]);
	}
	for(int i=0; i<n-1; i++){
		for(int j=0; j<n-i-1; j++){
			a[i][j]+=a[n-1-j][n-i-1];
		}
	}
}

void addedge(int u, int v, int wi)
{
	to[tot]=v, nxt[tot]=head[u], w[tot]=wi, head[u]=tot++;
}
void BuildGraph()
{
	for(int i=0; i<n-1; i++){
		for(int j=0; j<n-i-1; j++){
			for(int k=0; k<4; k++){
				int xi=i+dir[k][0];
				int yi=j+dir[k][1];
				if(xi<0||xi>=n||yi<0||yi>=n) continue;
				int u=i*n+j, v=xi*n+yi;
				addedge(u, v, a[xi][yi]);
			}
		}
	}
}
void spfa()
{
	int u=0, v, wi;
	q.push(u);
	vis[u]=1, dis[u]=0;
	while(!q.empty())
	{
		u=q.front(); q.pop();
		vis[u]=false;
		for(int i=head[u]; i!=-1; i=nxt[i])
		{
			v=to[i], wi=w[i];
			if(dis[v]==dis[u]+wi)
			{
				fa[v].push_back(u);
			}
			if(dis[v]>dis[u]+wi)
			{
				fa[v].clear();
				dis[v]=dis[u]+wi;
				fa[v].push_back(u);
				if(!vis[v]) vis[v]=true, q.push(v);
			}
			
		}
	}
}

ll dfs(int u)
{
	if(u==0) dp[u]=1;
	ll ret=0;
	if(dp[u]) return dp[u];
	for(int i=0; i<fa[u].size(); i++){
		ret = (ret+dfs(fa[u][i]))%mod;
	}
	return dp[u]=ret;
}

int main()
{
	while(~scanf("%d", &n))
	{
		if(n==0) break;
		init();
		input();
		BuildGraph();
		spfa();
		int minx=0x3f3f3f3f;
		for(int i=0; i<n; i++) {
			int j=n-1-i;
			minx = min(minx, dis[i*n+j]);
		}
		ll ans=0;
		for(int i=0; i<n; i++)
		{
			int j=n-1-i;
			if(dis[i*n+j]==minx) {
				ans = (ans+dfs(i*n+j))%mod;
			} 
		}
		printf("%d\n", ans);
	}
	return 0;
}/*2
1 1
1 1
3
1 1 1
1 1 1
2 1 1*/

H 【UVA 12296】 Pieces and Discs


I  【UVA 12297Super Poker


J 【UVA 12298】 Super Poker II


K 【UVA 12299】 RMQ with Shifts

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值