编程之美初赛第二场AB

题目1 : 扑克牌

时间限制:2000ms

单点时限:1000ms

内存限制:256MB

描述

一副不含王的扑克牌由52张牌组成,由红桃、黑桃、梅花、方块4组牌组成,每组13张不同的面值。现在给定52张牌中的若干张,请计算将它们排成一列,相邻的牌面值不同的方案数。

牌的表示方法为XY,其中X为面值,为2、3、4、5、6、7、8、9、T、J、Q、K、A中的一个。Y为花色,为S、H、D、C中的一个。如2S、2H、TD等。

输入

第一行为一个整数T,为数据组数。

之后每组数据占一行。这一行首先包含一个整数N,表示给定的牌的张数,接下来N个由空格分隔的字符串,每个字符串长度为2,表示一张牌。每组数据中的扑克牌各不相同。

输出

对于每组数据输出一行,形如"Case #X: Y"。X为数据组数,从1开始。Y为可能的方案数,由于答案可能很大,请输出模264之后的值。

数据范围

1 ≤ T ≤ 20000

小数据

1 ≤ N ≤ 5

大数据

1 ≤ N ≤ 52

样例输入
5
1 TC
2 TC TS
5 2C AD AC JC JH
4 AC KC QC JC
6 AC AD AS JC JD KD
样例输出
Case #1: 1
Case #2: 0
Case #3: 48
Case #4: 24
Case #5: 120

设dp[a][b][c][d][l]状态为当前某面值的牌只存一张的有a种,面值牌剩两张的有b种,如此类推,最后是上一个操作是对一张、两张。。。的操作。如l=3,则对三张的操作,会使得c-1,b+1。可以看到是记忆化搜索。注意的是,当上一前操作如l=3时,如果当前操作减少两张的,则应该是有(b-1)种可能,因为当前的b有一种是不能添加的,会造成相邻同面值。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define uLL unsigned long long
using namespace std;

uLL dp[15][15][15][15][5];

int counts[15];
int sum[5];
char stin[5];
bool vis[15][15][15][15][5];

int check(char s){
	if(s== ‘A‘) return 1;
	if(s== ‘T‘) return 10;
	if(s== ‘J‘) return 11;
	if(s== ‘Q‘) return 12;
	if(s== ‘K‘) return 13;
    return s-‘0‘;
}

uLL dfs(int a,int b,int c,int d,int l){
	if(dp[a][b][c][d][l]) return dp[a][b][c][d][l];
	if(a){
		dp[a][b][c][d][l]+=dfs(a-1,b,c,d,1)*(a-(l==2?1:0));
	}
	if(b) dp[a][b][c][d][l]+=dfs(a+1,b-1,c,d,2)*(b-(l==3?1:0));
	if(c) dp[a][b][c][d][l]+=dfs(a,b+1,c-1,d,3)*(c-(l==4?1:0));
	if(d) dp[a][b][c][d][l]+=dfs(a,b,c+1,d-1,4)*d;
	return dp[a][b][c][d][l];
}

int main(){
	int T,icase=0,n;
	memset(dp,0,sizeof(dp));
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		memset(counts,0,sizeof(counts));
		memset(sum,0,sizeof(sum));
		for(int i=1;i<=n;i++){
			scanf("%s",stin);
			counts[check(stin[0])]++;
		}
		for(int i=1;i<=13;i++){
			sum[counts[i]]++;
		}
		for(int i=1;i<=4;i++){
			dp[0][0][0][0][i]=1;
		}
		uLL ans=dfs(sum[1],sum[2],sum[3],sum[4],0);
		for(int i=1;i<=13;i++){
			for(int j=1;j<=counts[i];j++)
			ans*=j;
		}
		printf("Case #%d: %llu\n",++icase,ans);
	}
	return 0;
}

  

题目2 : 攻城略地

时间限制:2000ms

单点时限:1000ms

内存限制:256MB

描述

A、B两国间发生战争了,B国要在最短时间内对A国发动攻击。已知A国共有n个城市(城市编号1, 2, …, n),城市间有一些道路相连。每座城市的防御力为w,直接攻下该城的代价是w。若该城市的相邻城市(有道路连接)中有一个已被占领,则攻下该城市的代价为0。

除了占领城市,B国还要摧毁A国的交通系统,因而他们需要破坏至少k条道路。由于道路损毁,攻下所有城市的代价相应会增加。假设B国可以任意选择要摧毁的道路,那么攻下所有城市的最小代价是多少?

输入

第一行一个整数T,表示数据组数,以下是T组数据。

每组数据第一行包含3个整数n, m, k。

第二行是n个整数,分别表示占领城市1, 2, …, n的代价w。

接下来m行每行两个数i, j,表示城市i与城市j间有一条道路。

输出

对于每组数据输出一行,格式为"Case #X: Y"。X表示数据编号(从1开始),Y为答案。

数据范围

1 ≤ T ≤ 30

k ≤ m

0 ≤ w ≤ 108

小数据

1 ≤ n ≤ 1000

0 ≤ m ≤ 5000

大数据

1 ≤ n ≤ 106

0 ≤ m ≤ 106

样例输入
2
4 4 2
6 5 3 4
1 2
1 3
2 3
2 4
4 4 4
6

可以很明显知道,对一个连通分量,只需选择最小的一点攻克即可。那么,也可以知道,如果减少的边使连通分量变成一棵树,而边数又大于k,则只需攻克各自最小的那些点即可。否则,对于一棵树,任意减少一条边,最多增加一个连通分量。但希望把连通分量中最小值最小化,因此,把所有的点排序,从左往右,对于树,只需去掉不是最小值点的最小值的边,划分出一个连通分量即可。(代码WA,不知为何。。)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define LL long long
using namespace std;

const int MAXN=1000150;
bool vis[MAXN],pre[MAXN];
struct Point{
	int v,p;
}cities[MAXN];

int find(int x){
	int r=x;
	while(pre[r]!=r){
		r=pre[r];
	}
	while(pre[x]!=x){
		int t=pre[x];
		pre[x]=r;
		x=t;
	}
	return r;
}

void Union(int u,int v){
	int fu=find(u);
	int fv=find(v);
	if(fu!=fv){
		pre[fu]=fv;
	}
}

bool cmp(Point a,Point b){
	if(a.v<b.v) return true;
	return false;
}

int main(){
	int T,n,m,k,u,v,icase=0;
	scanf("%d",&T);
	while(T--){
		scanf("%d%d%d",&n,&m,&k);
		for(int i=1;i<=n;i++){
			scanf("%d",&cities[i].v);
			cities[i].p=i;
			pre[i]=i;
		}
		for(int i=1;i<=m;i++){
			scanf("%d%d",&u,&v);
			Union(u,v);
		}
		sort(cities+1,cities+1+n,cmp);
		LL ans=0; int tot=0;
		memset(vis,false,sizeof(vis));
		for(int i=1;i<=n;i++){
			int t=find(cities[i].p);
			if(!vis[t]){
				ans+=cities[i].v;
				tot++;
				vis[t]=true;
			}
		}
		printf("Case #%d: ",++icase);
		if(m-k>=n-tot){
			printf("%lld\n",ans);
		}
		else{
			k-=m-(n-tot);
			memset(vis,false,sizeof(vis));
			for(int i=1;i<=n&&k>0;i++){
				if(!vis[pre[cities[i].p]]){
					vis[pre[cities[i].p]]=true;
					continue;
				}
				ans+=cities[i].v;
				k--;
			}
			printf("%lld\n",ans);
		}
	}
}

  

时间: 2024-08-29 23:16:56

编程之美初赛第二场AB的相关文章

编程之美初赛第二场 集合

题目3 : 集合 时间限制:12000ms 单点时限:6000ms 内存限制:256MB 描述 统计满足下列条件的集合对(A, B)的数量: A,B都是{1, 2, -, N}的子集: A,B没有公共的元素: f(A)<= f(B).f(S)定义为S中所有元素的按位异或和.例如, f({}) = 0, f({1, 3}) = 2. 因为答案可能很大,你只需要求出它除以M的余数. 输入 第一行一个整数T (1 ≤ T ≤ 10),表示数据组数. 接下来是T组输入数据,测试数据之间没有空行. 每组数

2015编程之美初赛第二场扑克牌

一副不含王的扑克牌由52张牌组成,由红桃.黑桃.梅花.方块4组牌组成,每组13张不同的面值.现在给定52张牌中的若干张,请计算将它们排成一列,相邻的牌面值不同的方案数. 牌的表示方法为XY,其中X为面值,为2.3.4.5.6.7.8.9.T.J.Q.K.A中的一个.Y为花色,为S.H.D.C中的一个.如2S.2H.TD等. 输入 第一行为一个整数T,为数据组数. 之后每组数据占一行.这一行首先包含一个整数N,表示给定的牌的张数,接下来N个由空格分隔的字符串,每个字符串长度为2,表示一张牌.每组数

微软2014编程之美初赛第二场——题目2 : 字符串压缩

[来源] 题目2 : 字符串压缩 [分析] 把游程编码恢复为原始字符串,然后得出每一行的字符串的内容,放在一个vector中.用map统计vector中每一行的反复的次数. 比較两个游程编码得到的map是否同样就可以. 该算法占用空间太多,小数据AC,大数据MLE了. [代码] #include <iostream> #include <string> #include <vector> #include <map> #include <sstream

微软2014编程之美初赛第一场——题目2 : 树

[来源] 题目2 : 树 [分析] 依据输入情况建立起树的模型.树的表示是一个表明父亲节点的数组.核心算法有两个: 计算某一节点的深度.用循环实现,一直向上找父亲节点,直到找到根节点.计算循环的次数即为深度. 计算某一节点的全部子节点.用递归实现. 本题在实现上节点的命名从0至N-1,与题目描写叙述不同. [代码] #include <iostream> #include <vector> using namespace std; vector<int> childre

微软2014编程之美初赛第一场——题目3 : 活动中心

[来源] 题目3 : 活动中心 [分析] 本题採用的是三分法. 输入的一组点中找出左右边界.作为起始边界. while(右边界-左边界<精度){ 将左右边界构成的线段均匀分成3段,推断切割点的距离关系,抹去距离大的一段.更新左右边界. } 输出左(右)边界 [代码] #include <iostream> #include <vector> #include <cmath> #include <iomanip> using namespace std;

编程之美2015初赛第二场AB

题目1 : 扑克牌 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 一副不含王的扑克牌由52张牌组成,由红桃.黑桃.梅花.方块4组牌组成,每组13张不同的面值.现在给定52张牌中的若干张,请计算将它们排成一列,相邻的牌面值不同的方案数. 牌的表示方法为XY,其中X为面值,为2.3.4.5.6.7.8.9.T.J.Q.K.A中的一个.Y为花色,为S.H.D.C中的一个.如2S.2H.TD等. 输入 第一行为一个整数T,为数据组数. 之后每组数据占一行.这一行首先包含一个

编程之美初赛第一场--焦距

题目1 : 焦距 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描写叙述 一般来说.我们採用针孔相机模型,也就是觉得它用到的是小孔成像原理. 在相机坐标系下,一般来说,我们用到的单位长度.不是"米"这种国际单位,而是相邻像素的长度.而焦距在相机坐标系中的大小,是在图像处理领域的一个很重要的物理量. 如果我们已经依据相机參数,得到镜头的物理焦距大小(focal length),和相机胶片的宽度(CCD width),以及照片的横向分辨率(image width),

2015编程之美初赛第一场 A 彩色的树

时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 给定一棵n个节点的树,节点编号为1, 2, -, n.树中有n - 1条边,任意两个节点间恰好有一条路径.这是一棵彩色的树,每个节点恰好可以染一种颜色.初始时,所有节点的颜色都为0.现在需要实现两种操作: 1. 改变节点x的颜色为y: 2. 询问整棵树被划分成了多少棵颜色相同的子树.即每棵子树内的节点颜色都相同,而相邻子树的颜色不同. 输入 第一行一个整数T,表示数据组数,以下是T组数据. 每组数据第一行是n,表示树的节

2015编程之美初赛第一场 C 质数相关

 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 两个数a和 b (a<b)被称为质数相关,是指a × p = b,这里p是一个质数.一个集合S被称为质数相关,是指S中存在两个质数相关的数,否则称S为质数无关.如{2, 8, 17}质数无关,但{2, 8, 16}, {3, 6}质数相关.现在给定一个集合S,问S的所有质数无关子集中,最大的子集的大小. 输入 第一行为一个数T,为数据组数.之后每组数据包含两行. 第一行为N,为集合S的大小.第二行为N个整数,表示集