给出一个字符串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;
}
给出一个数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;
}
给出一个序列,问在其中找一个子序列,这个子序列先非严格递增后非严格递减
说白了就是求两次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;
}
就是让你求猴子排序的成功概率
对于每一个字母,放在第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)
两个人在一个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;
}
给出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;
}