1-Alice Game
题意 n
个怪物排成一排,每次选择下列操作之一,Alice
先手
- 选择长度小于等于
k
的连续序列,kill
选择的怪物 - 选择长度为
k
的连续序列,kill
这些怪物,并且将两侧的非空序列独立为俩序列
Tag sg
打表找规律
题解 首先枚举,可知 x <= k
时候永远能使得 Alice
胜利,x = k + 1
时候,永远是 Bob
胜利,因此先看第二次操作
先打表找规律,f
是记忆化搜索,依次枚举 i
,得到 j = x - i - k
,递归算出每个点的 sg
值,最后取 mex
---========-------
i k j
#include <iostream>
#include <cstring>
#include <set>
using namespace std;
const int N = 1e5 + 2;
int k, f[N];
int sg(int x) {
if (f[x] != -1) return f[x];
set<int> s;
for (int i = 1; i <= x; i ++) {
int j = x - i - k;
if (j <= 0) continue;
s.insert(sg(i) ^ sg(j));
}
for (int i = 0; ; i ++)
if (!s.count(i))
return f[x] = i;
}
int main() {
memset(f, -1, sizeof(f));
cin >> k;
f[0] = f[k + 1] = 0;
for (int i = 1; i <= k; i ++) f[i] = 1;
for (int i = k + 1; i <= 1000; i ++) f[i] = sg(i);
for (int i = 1; i <= 1000; i ++) {
if (f[i]) continue;
cout << i << ' ' << f[i] << endl;
}
}
由于打表很慢,总结出规律可直接写结果,极大降低复杂度
#include <iostream>
using namespace std;
int main() {
int T; cin >> T;
while (T--) {
int n, k;
cin >> k >> n;
int len = k * 4 + 2;
n %= len;
if (n == 0) n = len;
if (n == k + 1) puts("Bob");
else puts("Alice");
}
}
2-Binary Number
题意 给定 01
序列,进行 k
次翻转操作(0
变 1
,1
变 0
),找出操作后的最大字典序序列
题解 需要多次特判
#include <iostream>
using namespace std;
typedef long long ll;
int n, m;
string solve() {
ll n, k; cin >> n >> k;
string s; cin >> s;
if (k == 0) return s;
string ans = s;
int idx = 0, cnt = 0;
for (int i = 1; i < n; i ++) {
if (s[i] == '1') cnt ++;
if (k == 0 && s[i] == '1') break;
if (s[i] == '0') {
if (s[i - 1] == '1') k --;
ans[i] = '1';
}
}
if (cnt == n - 1 && k == 1 || n == 1 && k & 1)
ans[n - 1] = '0';
return ans;
}
int main() {
int T; cin >> T;
while (T --) cout << solve() << endl;
return 0;
}
4-Card Game
题意 汉诺塔,但是给定有多少个塔,计算能放的最多盘子
Tag 快速幂
题解 枚举后发现答案为 2 n − 1 − 1 2^{n - 1} - 1 2n−1−1,快速幂即可
#include <iostream>
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int mod = 998244353;
int n, m;
int qpow(int a, int k) {
int res = 1;
while (k) {
if (k & 1) res = (ll)res * a % mod;
a = (ll)a * a % mod;
k >>= 1;
}
return res;
}
int main() {
int T; cin >> T;
while (T --) {
int x; cin >> x;
cout << (qpow(2, x - 1) - 1 + mod) % mod << '\n';
}
return 0;
}
7-foreverlasting and fried-chicken
题意 左上角为目标图形,右下角为样例图,求所给图中有多少个目标图形
题解 如样例,枚举特征点 1
和 8
,再找有多少个公共点,最后组合数和乘法原理求解,可以用快速幂求逆元,也可直接 __int128
,🤣🤣🤣,赛时用的 vector
一直 TLE
,换成 bitset
能极大优化复杂度,bitset的使用详见->
#include <iostream>
#include <vector>
#include <set>
#include <bitset>
#define endl '\n'
using namespace std;
typedef long long ll;
const int N = 1e3 + 2, mod = 1e9 + 7;
int n, m, last;
bitset<N> bt[N];
ll C2(ll x) {
return x * (x - 1) / 2 % mod;
}
ll C4(ll xx) {
__int128 x = xx;
__int128 res = x * (x - 1) * (x - 2) * (x - 3) / 24 % mod;
ll ans = res;
return ans;
}
ll solve() {
cin >> n >> m;
ll res = 0;
for (int i = 1; i <= n; i ++) bt[i].reset();
for (int i = 0; i < m; i ++) {
int a, b; cin >> a >> b;
bt[a][b] = bt[b][a] = 1;
}
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= n; j ++) {
int cnt_i = bt[i].count();
int cnt_j = bt[j].count();
if (bt[i][j]) cnt_i --, cnt_j --;
int cnt = (bt[i] & bt[j]).count();
if (cnt_i < 6 || cnt < 4 || j == i) continue;
(res += C2(cnt_i - 4) * C4(cnt)) %= mod;
}
}
return res;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int T; cin >> T;
while (T --) cout << solve() << endl;
return 0;
}
9-String Problem
题意 计算连续的子串的 len
,求最大
∑
K
i
=
1
l
e
n
(
s
i
)
−
K
\sum_{K}^{i = 1} len(s_{i} ) - K
∑Ki=1len(si)−K
#include<iostream>
using namespace std;
int solve() {
string s; cin >> s;
int res = 0, cnt = 1;
for (int i = 1; i < s.size(); i++) {
if (s[i] == s[i - 1]) cnt ++;
else {
res += cnt - 1;
cnt = 1;
}
}
if (cnt) res += cnt - 1;
return res;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
int T; cin >> T;
while (T --) cout << solve() << endl;
return 0;
}