题目: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;
}
}
}