【牛客网】新疆大学ACM-ICPC程序设计竞赛五月月赛(同步赛)

比赛链接

A Red Rover

给出一个字符串S,现在让你选取一个子串S',用字母M代替S中的所有子串,

问代替后的字符串S的长度加上S'的长度的最小值是多少

(特意图片题目是,,防止复制翻译流?)


因为字符串只有100,所以n^2枚举字串吧,

匹配方面能用再n^2可能吃不消(虽然应该是可以的?)所以稳健一点kmp吧

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
using namespace std;
const int maxn = 5*int(1e5)+100;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
typedef long long LL;
typedef unsigned long long ull;
char ori[200], par[200];//原串,模式串
int len1, len2, nexts[200];
void getnext() {//得到模式串的next跳表
	nexts[0] = -1;
	int i = 0, j = -1;
	while (i<len2) {
		if (j == -1 || par[i] == par[j])
			nexts[++i] = ++j;
		else
			j = nexts[j];
	}
}
int kmp() {
	getnext();
	int i = 0, j = 0, ans = 0;
	while (i < len1) {
		if (j == -1 || ori[i] == par[j]) {
			i++, j++;
		}
		else j = nexts[j];
		if (j == len2) {
			ans++;
			j = 0;//与上面的区别,重新开始匹配
		}
	}
	return ans;
}
int main() {
	while (~scanf("%s", ori)) {
		len1 = strlen(ori);
		int ans = len1;
		for (int i = 0; i < len1; i++) {
			memset(par, 0, sizeof(par));
			len2 = 0;
			for (int j = i; j < len1; j++) {
				par[len2++] = ori[j];
				int tmp = kmp();
				ans = min(ans, len1 - len2*tmp + tmp + len2);
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}

B 杨老师的游戏

给出一个数n,让你用数字1~9构造算式a*b-c=n

问构造的方法有多少种(1~9必须都用上而且只能用一次)


直接三重循环暴力吧

这里笔者暴力用next_permutation直接全排列1~9

读者也可以考虑用dfs

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
using namespace std;
const int maxn = 3000;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
typedef long long LL;
typedef unsigned long long ull;
int main() {
	LL x;
	scanf("%lld", &x);
	LL d[] = { 1,2,3,4,5,6,7,8,9 };
	int ans = 0;
	do {
		LL a, b, c;
		a = 0;
		for (int i = 0; i < 7; i++) {
			a = a * 10 + d[i];
			b = 0;
			for (int j = i + 1; j < 8; j++) {
				b = b * 10 + d[j];
				c = 0;
				for (int k = j + 1; k < 9; k++) {
					c = c * 10 + d[k];
				}
				if (a*b - c == x) ans++;
			}
		}
	} while (next_permutation(d, d + 9));
	printf("%d\n", ans);
	return 0;
}

C 勤奋的杨老师

给出一个序列,问在其中找一个子序列,这个子序列先非严格递增后非严格递减

说白了就是求两次lis,,

不过有一点要注意的是nlogn的lis dp数组记录的不是以某一位为结尾的最长子序列(这种记法的是n^2的)

所以要另外设一个数组保存信息,

然后对这两个记录数组,找出他们的 dp1[i] + dp2[i] - 1 的最大值

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
using namespace std;
const int maxn = 5*int(1e5)+100;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
typedef long long LL;
typedef unsigned long long ull;
int dp1[maxn], dp2[maxn];
int lis1[maxn], lis2[maxn];
int num[maxn];
int main() {
	int n;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf("%d", &num[i]);
	int len = 0;
	lis1[0] = 0;
	for (int i = 1; i <= n; ++i) {
		if (num[i] >= lis1[len])
			lis1[++len] = num[i];
		else {
			int pos = upper_bound(lis1 + 1, lis1 + len + 1, num[i]) - lis1;
			lis1[pos] = num[i];
		}
		dp1[i] = len;
	}
	len = 0;
	lis2[0] = 0;
	for (int i = n; i >0; --i) {
		if (num[i] >= lis2[len])
			lis2[++len] = num[i];
		else {
			int pos = upper_bound(lis2 + 1, lis2 + len + 1, num[i]) - lis2;
			lis2[pos] = num[i];
		}
		dp2[i] = len;
	}
	int sum = 1;
	for (int i = 1; i <= n; i++) {
		if (dp2[i] != len&&sum < dp1[i] + dp2[i] - 1)
			sum = dp1[i] + dp2[i] - 1;
	}
	printf("%d\n", sum);
	return 0;
}

F 猴子排序的期望

就是让你求猴子排序的成功概率

对于每一个字母,放在第i个位置的概率是


其中cnt表示这种字母的个数,ues表示之前用了几个

实际上这个公式可以写成  每种字母数目的阶乘的乘积 /总阶乘

读者可能已经发现了,,没错因为题目给出的n是100,

100的阶乘明显要你用高精度

所以这里唯一的坑也是最大的坑就是,这个需要高精度乘法

不过py大法好

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
n=int(input())
string=input()
string=sorted(string)
sum=1
for i in range(1,n+1):
    sum*=i
t=1
for i in range(0,len(string)-1):
    if(string[i]==string[i+1]):
        t=t+1
    else:
        t=1
    sum=sum//t
print("1/%d"%sum)

G chess

两个人在一个1000*1000的棋盘上移动皇后

每轮每人能移动一次,皇后移动规则和国际象棋一致,

谁先把皇后移动到左下角谁就赢

现在给出皇后的相对于棋盘左边的和棋盘下边的位置,问谁赢


说实话一开始真没看出什么,

不过比划比划之后发现,如果在最优解的情况下

每人每次能让皇后的  其中一个坐标减少任意数,或者两个坐标同时减少任意数。。。

这不就是威佐夫博奕吗(可怕)

所以直接上威佐夫博奕的结论

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
using namespace std;
const int maxn = 5*int(1e5)+100;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
typedef long long LL;
typedef unsigned long long ull;
int main() {
	int n, m;
	while (~scanf("%d%d", &n, &m)) {
		if (n < m) swap(n, m);
		int x = int((sqrt(5) + 1) / 2 * (n - m));
		if (x == m) printf("Lao Wang\n");
		else printf("Xiao Ren\n");
	}
	return 0;
}

H XOR

给出n个点,点的编号0~(n-1)

两个点之间的权值为点编号的异或值,

现在让你找出一个最小生成树,输出该生成树的总权


摸不着头脑的题

画一下n在1~5的图大概摸清了规律

对于编号x而言,找一个编号y(x>y)使边权最小的话,

显然是把x除最右的1全弄个掉的最优,而这样的数一定是比x小的。

之所以不是把x所有的1全弄掉并在后面异或出1是因为这样的数一定比x大,不考虑

这里之所以不讨论比x大的数是因为大小关系是可以互换的。


读者应该已经察觉到了,这种求法就是树状数组中的lowbit函数(无奈)

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
using namespace std;
const int maxn = 5*int(1e5)+100;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
typedef long long LL;
typedef unsigned long long ull;
int lowbit(int x) {
	return x&(-x);
}
int main() {
	int n;
	while (~scanf("%d", &n)) {
		int ans = 0;
		for (int i = 0; i < n; i++)
			ans += lowbit(i);
		printf("%d\n", ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xiuya19/article/details/80168479