队内排位赛(一)

题目:http://codeforces.com/group/5yyKg9gx7m/contest/269717

A

题目大意:

有n头牛,每头牛有k个属性,以及它们在每个属性的排名,求有多少对牛,使其中一头牛的每个属性排名都高于另外一头牛

题目分析:

因为n、k很小,直接暴力枚举

代码
#include <iostream>
using namespace std;
int n,k;
struct Cow
{
	int rank[50];
 } cow[50];
bool check(int x, int y)
{
	for(int i = 1; i <= k; i ++)
	if(cow[x].rank[i] >= cow[y].rank[i])return false;
	return true;	
}
int main()
{
	cin >> k >>n;
	for(int i = 1; i <= k; i++)
	for(int j = 1; j <= n;j ++)
	{
		int x;
		cin >> x;
		cow[x].rank[i] = j;
	}
	int ans = 0;
	for(int i = 1; i <= n;i++)
	for(int j = 1; j <= n;j++)
	if(i!=j&&check(i,j))
		ans ++;
	cout << ans;
	return 0;
} 

B

题目大意:

求第n个能被3或5整除的正整数。

题目分析:

显然能被3或5整除的数是以15为一个周期分布的。

代码:
#include <iostream>
using namespace std;
typedef long long LL;
LL n;
int main()
{
	cin >> n;
	LL ans = (n/8) * 15;
	LL d[20] = {0,1,2,4,7,8,11,13,14};
	ans = ans + d[n%8];
	if(n % 8 == 0)cout<<(n/8)*15 - 1;
	else cout << ans; 
	return 0;
} 

C

题目大意:

给你一个只有m个小写字母的字符串ch(a=1,b=2,…,z=26),长度为n,给出修改i为j的代价a[i][j],要求你修改该字符串,使得对于任意i,x,y(0<=x<i<y<=n+1),若ch[x]!=ch[i],ch[y]!=ch[i],则y-x-1>=k(ch[0]=ch[n+1]=0)。

题目分析

首先需要求把i修改为j的最小代价,这个可以用Floyd算法直接求出

然后因为涉及到最优子结构,想到了动规。

不难想出若定义f[i][j]为对于前i个字母的字符串,修改后第i个字母为j的最小代价。而状态转移的大概思路就是对于第i个字母,有两个选择:
1.开辟一段新的字母:f[i][j] = min( f[i-k][t] + a[ch[i-k+1]][j]+a[ch[i-k+2]][j]+…+a[ch[i]][j] )(1<=t<=m)
2.跟随上一个字母:f[i][j] = f[i-1][j] + a[ch[i]][j];

而这种时间复杂度为O(mn2)显然不能接受
而对于O(n)操作: a[ch[i-k+1]][j]+a[ch[i-k+2]][j]+…+a[ch[i]][j] 显然可以用前缀和数组s[i][j] (前i个字母全部修改为j的代价)来优化变为O(1)
最后时间复杂度就为O(mn)了

代码
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10, M = 40;
LL a[M][M],s[N][M],m,n,k,f[N][M];
char ch[N];
int main()
{
	//读入数据 
	cin >> n >> m >> k;
	cin >> ch+1;
	for(int i = 1; i <= n; i ++)
	ch[i] -= 'a'-1;
	for(int i = 1; i <= m; i ++)
	for(int j = 1; j <= m; j ++)
	scanf("%d",&a[i][j]);
	
	//Floyd 求最短路 
	for(int t = 1; t <= m; t ++)
	for(int i = 1; i <= m; i ++)
	for(int j = 1; j <= m; j ++)
	a[i][j] = min(a[i][j],a[i][t]+a[t][j]);
	
	//s前缀和数组 
	for(int i = 1; i <= n; i ++)
	for(int t = 1; t <= m; t ++)
	s[i][t] = s[i-1][t] + a[ch[i]][t];
	
	//只能有一段相同字母 
	for(int i = 1; i < k*2&&i<=n; i ++)
	for(int t = 1; t <= m; t ++)
	f[i][t] = s[i][t];
	
	//可以有多段相同字母 
	for(int i = k*2; i <= n; i ++)
	for(int j = 1; j <= m; j ++)
	{ 
		LL x = -1;
		for(int t = 1; t <= m; t ++)
		if(x==-1||x>f[i-k][t])x = f[i-k][t];
		x += s[i][j] - s[i-k][j];
		
		f[i][j] = min(x,f[i-1][j]+a[ch[i]][j]);
	}
	
	LL ans = -1;
	for(int i = 1; i <= m; i ++)
	if(ans==-1||ans>f[n][i])ans = f[n][i];
	cout << ans;
	return 0;
 } 

G

题目大意:

有8头牛排成一列,给定一些如A牛必须在B牛旁的限制,求字典序最小的排列

题目解析:

因为牛很少,所以直接dfs一波就过了

代码
#include <iostream>
using namespace std;
typedef long long LL;
LL n;
string cow[8] = {"Beatrice","Belinda","Bella","Bessie","Betsy","Blue","Buttercup","Sue"};
int a[8] = {0,1,2,3,4,5,6,7};
int lim[100][2],ans[10];
bool st[10];
void dfs(int now, bool &flag)
{
	if(flag)return;
	if(now == 8)
	{
		for(int i = 1; i <= n; i ++)
		if(ans[lim[i][0]] - ans[lim[i][1]]!= 1 &&ans[lim[i][0]] - ans[lim[i][1]]!= -1)
			return;
		flag = true;
	}
	for(int i = 0; i < 8&&!flag; i ++)
		if(!st[i]&&flag == false)
		{
			st[i] = true;
			ans[i] = now;
			dfs(now+1,flag);
			st[i] = false;
		}
}
int main()
{
	cin >> n;
	for(int k = 1; k <= n; k++)
	{
		string s;
		for(int i = 1; i <= 6; i ++)
		{
			cin >> s;
			if(i == 1)
			for(int j = 0; j < 8; j ++)
			if(cow[j]==s)lim[k][0] = j;
			
			if(i == 6)
			for(int j = 0; j < 8; j ++)
			if(cow[j]==s)lim[k][1] = j;
		}
	}
	bool flag =false;
	dfs(0,flag);
	for(int i = 0; i < 8; i ++)
	for(int j = 0; j < 8; j++)
	if(ans[j]==i)cout << cow[j] << endl;
	return 0;
} 

I

题目大意:

给你一个由大写字母组成的字符串,求最小k,使得在任何连续k个字母中能唯一确定这k个字母的位置

题目分析:

暴力枚举k!!!

代码
#include <iostream>
using namespace std;
char s[110];
int n;
bool check(int x, int y, int k)
{
	for(int i = 0; i < k; i ++)
		if(s[x+i]!=s[y+i]) return false;
	return true;
}
int main()
{
	
	cin >> n;
	cin >> s;
	for(int k = 1; k <= n; k ++)
	{
		bool flag = true;
		for(int i = 0; i < n&&flag; i ++)
		for(int j = i + 1; j+k-1 < n &&flag; j ++)
		if(check(i,j,k))flag = false;
		if(flag)
		{
			cout << k;
			return 0;
		}
	}
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值