12.18 update:补充了 $ F $ 题的题解ios
A 题:c++
题目保证必定有解,就能够考虑用 $ 2 $ 和 $ 3 $ 来凑出这个数 $ n $spa
若是 $ n $ 是偶数,咱们用 $ n / 2 $ 个 $ 2 $ 来凑出 $ n $ 便可code
若是 $ n $ 是奇数,就用 $ n / 2 - 1 $ 个 $ 2 $ 和 $ 1 $ 个 $ 3 $ 凑出 $ n $ 便可字符串
因此只需输出 $ n / 2 $get
B 题:it
若是一个字符串重排后必定是回文串,说明这个字符串只有 $ 1 $ 种字符io
若是有两种不一样字符,就能够把一个放在开头,一个放在结尾,这样造成的必定不是回文串class
一个简单一点的写法是 $ sort $ 一下这个字符串,判断回文date
C 题:
贪心的想,咱们若是要使整个序列非降,那么前面的数字要尽可能小,后面的数字要尽可能大
首先 $ a[1] = 0,a[n] = b[1] $,而后贪心的扫过去,在知足条件的状况下使得前面的数字尽可能小,后面的数字尽可能大便可
D 题:
发现每条边的两个端点的数字的奇偶性必定不一样
因此咱们咱们只要作一次 $ bfs $ 染色并判断是否能完成染色便可
假设黑点有 $ a $ 个,白点有 $ b $ 个
若是黑点是奇数,方案数是 $ 2^a $ 种,若是白点是奇数,方案数是 $ 2^b $ 种,总方案数是 $ 2^a + 2^b $ 种
而后发现整个图不必定联通
因此咱们对每一个联通块作一次 $ bfs $ 染色,而后把答案相乘便可
注意不能用 memset,否则 $ T $ 组数据每次 memset 一次确定凉
E 题:
用 $ pa[i] $ 表示 $ i $ 这个数在第一个排列中出现的位置,$ pb[i] $ 表示 $ i $ 这个数在第二个排列中出现的位置
假设查询区间为 $ l1,r1,l2,r2 $
若是 $ i $ 这个点对答案形成了贡献,那么 $ l1 \le pa[i] \le r1 $ && $ l2 \le pb[i] \le r2 $
容易发现问题变成了二维数点问题,$ cdq $ 分治离线统计答案便可
F 题:
咕咕咕
补锅完毕
发现 $ len $ 的大小很是大,不能放进状态里,又发现 $ k \le 100 $,因此用 $ f[i][j] $ 表示第 $ i $ 个数是 $ j $ 且知足题目所述条件的方案数
发现不能很好的进行转移,因此再用 $ s[i] $ 表示 $ \sum_{j = 1}^{k} f[i][j] $,而后就是容斥转移一下
注意一下须要容斥的条件
能够根据代码理解一下
#include <bits/stdc++.h> #define CIOS ios::sync_with_stdio(false); #define rep(i, a, b) for(register int i = a; i <= b; i++) #define per(i, a, b) for(register int i = a; i >= b; i--) #define DEBUG(x) cerr << "DEBUG" << x << " >>> "; using namespace std; typedef unsigned long long ull; typedef long long ll; template <typename T> inline void read(T &f) { f = 0; T fu = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') fu = -1; c = getchar(); } while (c >= '0' && c <= '9') { f = (f << 3) + (f << 1) + (c & 15); c = getchar(); } f *= fu; } template <typename T> void print(T x) { if (x < 0) putchar('-'), x = -x; if (x < 10) putchar(x + 48); else print(x / 10), putchar(x % 10 + 48); } template <typename T> void print(T x, char t) { print(x); putchar(t); } const int N = 1e5 + 5, md = 998244353; inline int add(int x, int y) { x += y; if(x >= md) x -= md; return x; } inline int sub(int x, int y) { x -= y; if(x < 0) x += md; return x; } int f[N][105], cnt[N][105], s[N], a[N]; int n, k, len; int main() { read(n); read(k); read(len); if(len == 1) { cout << 0 << endl; return 0; } for(register int i = 1; i <= n; i++) read(a[i]); for(register int i = 1; i <= n; i++) { for(register int j = 1; j <= k; j++) cnt[i][j] = cnt[i - 1][j] + (a[i] == -1 || a[i] == j); } s[0] = 1; if(a[1] == -1) { for(register int i = 1; i <= k; i++) f[1][i] = 1; s[1] = k; } else f[1][a[1]] = 1, s[1] = 1; for(register int i = 2; i <= n; i++) { for(register int j = 1; j <= k; j++) { if(~a[i] && a[i] != j) continue; f[i][j] = s[i - 1]; if(i >= len) { int l = i - len; if(cnt[i][j] - cnt[l][j] == len) { f[i][j] = sub(f[i][j], sub(s[l], f[l][j])); } } s[i] = add(s[i], f[i][j]); } } cout << s[n] << endl; return 0; }
G 题:
习惯性的把曼哈顿距离的绝对值拆出来,用二进制表示
$ 31 $ 的二进制表示是 $ 11111 $,表示 $ 5 $ 维的一个点的坐标加入的正负状况都为正(即 $ x[1] - y[1] + x[2] - y[2] + x[3] - y[3] + x[4] - y[4] + x[5] - y[5] $
$ 29 $ 的二进制表示是 $ 11101 $,表示 $ x[1] - y[1] + x[2] - y[2] + x[3] - y[3] - x[4] + y[4] + x[5] - y[5] $ (注意 $ x[4] $ 和 $ y[4] $ 的符号变化
那么咱们要求的就是 max{f[0] + f[31], f[1] + f[30], f[2] + f[29]...}
用线段树维护便可