考场上几乎是一看就看出来轮廓线叻...可是调了两个小时打死也过不了手出样例!std发下来一对,特判对的啊,转移对的啊,$dp$数组竟然没有取max!!!

某位考生当场死亡。

结果下午又请了诸位dalao来看为什么剩下wa两个点!结果数组开小。

某位考生再次死亡。

#include<bits/stdc++.h>
#define RG register
using namespace std; int dp[][(<<)+], cnt[(<<)+];
int R, C, a[][];////////不开够影响很大!! int count(int sta) {
int num = ;
while(sta) {
if(sta & ) num ++;
sta >>= ;
}
return num;
} void init() {
scanf("\n");
for(int i = ; i <= R; i ++) {
char s; int cnt = ;
s = getchar();
while(s != '\n') {
a[i][++a[i][]] = s - 'A' + ;
s = getchar();
}
}
for(int i = ; i < ( << C); i ++)
cnt[i] = count(i);
} struct Node {
int n1, n2;
Node(int n1 = , int n2 = ) :
n1(n1), n2(n2) { }
}; inline Node check(int sta, int pos, int line) {
int s1 = sta >> (pos - ), s2 = sta & (( << (pos - )) - );
int num1 = cnt[s1], num2 = cnt[s2];
if(num1 > a[line-][] || num2 > a[line][] || num2 + C - pos + < a[line][] || num1 + pos - < a[line-][]) return Node(-, -);
return Node(num1, num2);
} int main() {
freopen("group.in", "r", stdin);
freopen("group.out", "w", stdout);
scanf("%d%d", &R, &C);
init();
int now = ;
for(RG int i = ; i <= R; i ++) {
for(RG int j = ; j <= C; j ++) {
now ^= ;
memset(dp[now], , sizeof(dp[now]));
for(RG int s = ; s < ( << C); s ++) {
int pre = s & ( << (C - )); int las = s & ;
Node opt = check(s, j, i);
if(opt.n1 == -) continue;
int q = opt.n1, p = opt.n2;
int num1, num2;
if(!pre) num1 = ;
else num1 = a[i-][a[i-][]-q+];
if(!las || j == ) num2 = ;
else num2 = a[i][p];
if(p + <= a[i][]) {
int ss = (s ^ pre) << | ;
int t = dp[now ^ ][s];
if(a[i][p+] == num1 && pre) t += ;
if(a[i][p+] == num2 && las) t += ;
dp[now][ss] = max(t, dp[now][ss]);////我暴毙
}
int ss = (s ^ pre) << ;
dp[now][ss] = max(dp[now][ss], dp[now ^ ][s]);
}
}
}
int ans = ;
for(int s = ; s < ( << C); s ++) {
if(cnt[s] != a[R][]) continue;
ans = max(ans, dp[now][s]);
}
printf("%d", ans);
return ;
}

我们可以发现在模数为质数时,可以直接用组合+求逆元计算出来,但是求逆元只能是在模数与要求逆元数互质时才行。

又因为题目明显暗示$MOD$由质数组成,所以直接套中国剩余定理即可。需要注意的是,对于每个分解出来的质因子都要重新求对应的逆元和阶乘。

#include<bits/stdc++.h>
#define LL long long
using namespace std; int n, m, T, MOD;
LL fac[], va[], vm[], inv[];
LL isnot[], prime[], t; void div() {
isnot[] = ;
for(int i = ; i <= ; i ++) {
if(!isnot[i])
prime[++t] = i;
for(int j = ; j <= t; j ++) {
int to = prime[j] * i;
if(to > ) break;
isnot[to] = ;
if(i % prime[j] == ) break;
}
}
} LL tot;
void init() {
div();
LL tmp = MOD;
for(LL i = ; i * i <= tmp && tmp != ; i ++)
if(tmp % i == ) vm[++tot] = i, tmp /= i;
if(tmp > ) vm[++tot] = tmp;
} LL mpow(LL a, LL b, LL mod) {
LL ans = ;
for(; b; b >>= , a = a * a % mod)
if(b & ) ans = ans * a % mod;
return ans;
} LL rev(LL a, LL mod) {
return mpow(a, mod - , mod);
} LL C(LL q, LL p, LL mod) {
if(p > q) return ;
return fac[q] * inv[p] % mod * inv[q-p] % mod;
} LL Lucas(LL x, LL y, LL mod) {
if(x < y) return ;
if(y == ) return ;
return Lucas(x / mod, y / mod, mod) * C(x % mod, y % mod, mod) % mod;
} LL Chinese_remainder_theorem() {
LL ans = ;
for(LL i = ; i <= tot; i ++) {
LL mi = MOD / vm[i];
LL rei = rev(mi, vm[i]);
ans = (ans + mi * rei % MOD * va[i] % MOD) % MOD;
}
return ans;
} int main() {
freopen("visit.in", "r", stdin);
freopen("visit.out", "w", stdout);
scanf("%d%d", &T, &MOD);
scanf("%d%d", &n, &m);
if(n < ) n = -n;
if(m < ) m = -m;
int c = (T - n - m) / ;
if(T < n + m || (n + m - T) % == ) {
printf("0\n"); return ;
}
init();
for(LL k = ; k <= tot; k ++) {
fac[] = ;
for(long long i = ;i <= T;i ++)
fac[i] = 1ll * fac[i-] * i % vm[k];
inv[] = inv[] = ;
for(long long i = ;i <= T;i ++)
inv[i] = 1ll * inv[vm[k] % i] * (vm[k] - vm[k] / i) % vm[k];
for(long long i = ;i <= T;i ++)
inv[i] = 1ll * inv[i] * inv[i - ] % MOD;
for(LL i = ; i <= c; i ++) {
LL j = c - i;
va[k] = (va[k] + 1ll * Lucas(T, i, vm[k]) * Lucas(T-i, j, vm[k]) % vm[k] * 1ll * Lucas(T-i-j, i+n, vm[k]) % MOD) % MOD;
}
}
LL ans = Chinese_remainder_theorem();
printf("%lld", ans);
return ;
}

由字符串的前缀和想到建$Trie$树。我们发现,对于$Trie$树上某一节点,如果它的儿子有一个是可以选择必胜,那么当前节点就可以选择必败;如果它的儿子有一个是可以选择必败,那么当前节点就可以选择必胜;如果它的儿子全都可胜可败,那么它就没有选择权利;如果它的儿子有一个没有选择权利,那么它就可胜可败。在$Trie$树上直接深搜处理出每个节点的状态。

出来后如果根节点可胜可败,那么$Pure$就可以选择前面所有局都输,最后胜,因此她必胜;如果根节点必败,那么$Dirty$必胜;如果根节点必胜,那么要看局数$k$的奇偶性;如果根节点无法选择,也是$Dirty$必胜。

#include<bits/stdc++.h>
using namespace std; int n, k;
int son[][], tail;
char str[]; void add(char *s) {
int nd = ; int len = strlen(s);
for(int i = ; i < len; i ++) {
int t = s[i] - 'a';
if(!son[nd][t]) son[nd][t] = ++ tail;
nd = son[nd][t];
}
} int dp[];
int Dfs(int u) {
int fl = -, sum = , num = ;
for(int i = ; i < ; i ++) {
if(son[u][i]) {
sum ++;
fl = Dfs(son[u][i]);
if(fl == ) dp[u] |= ;
if(fl == ) dp[u] |= ;
if(fl == ) dp[u] |= ;
if(fl == ) num ++;
}
}
if(num == sum) dp[u] = ;
if(fl == -) dp[u] = ;
return dp[u];
} int main() {
freopen("strGame.in", "r", stdin);
freopen("strGame.out", "w", stdout);
int T;
scanf("%d", &T);
while(T --) {
memset(son, , sizeof(son));
memset(dp, , sizeof(dp));
tail = ;
scanf("%d%d", &n, &k);
for(int i = ; i <= n; i ++) {
scanf("%s", str);
add(str);
}
Dfs();
if(dp[] == ) printf("Pure\n");
else if(dp[] == ) {
printf("Dirty\n");
} else if(dp[] == ) {
if(k % ) printf("Pure\n");
else printf("Dirty\n");
} else printf("Dirty\n");
}
return ;
}

【10.4校内测试】【轮廓线DP】【中国剩余定理】【Trie树+博弈】的更多相关文章

  1. 【10.29校内测试】【线段树】【DP】【二进制Trie树求最小值最大】

    Solution 标程太暴力惹QAQ 相当于是26棵线段树的说QAQ 不过我写了另一种写法,从大到小枚举每一个字母,标记字典序在这个字母之上的位置为1,每次都建一棵线段树,维护1的数量,即区间和. 修 ...

  2. 【10.17校内测试】【二进制数位DP】【博弈论/预处理】【玄学(?)DP】

    Solution 几乎是秒想到的水题叻! 异或很容易想到每一位单独做贡献,所以我们需要统计的是区间内每一位上做的贡献,就是统计区间内每一位是1的数的数量. 所以就写数位dp辣!(昨天才做了数字统计不要 ...

  3. 【10.31校内测试】【组合数学】【记忆化搜索/DP】【多起点多终点二进制拆位Spfa】

    Solution 注意取模!!! Code #include<bits/stdc++.h> #define mod 1000000007 #define LL long long usin ...

  4. 【10.26校内测试】【状压?DP】【最小生成树?搜索?】

    Solution 据说正解DP30行??? 然后写了100行的状压DP?? 疯狂特判,一算极限时间复杂度过不了aaa!! 然而还是过了....QAQ 所以我定的状态是待转移的位置的前三位,用6位二进制 ...

  5. 【10.5校内测试】【DP】【概率】

    转移都很明显的一道DP题.按照不优化的思路,定义状态$dp[i][j][0/1]$表示吃到第$i$天,当前胃容量为$j$,前一天吃(1)或不吃(0)时能够得到的最大价值. 因为有一个两天不吃可以复原容 ...

  6. 【10.3校内测试【国庆七天乐!】】【DP+组合数学/容斥】【spfa多起点多终点+二进制分类】

    最开始想的暴力DP是把天数作为一个维度所以怎么都没有办法优化,矩阵快速幂也是$O(n^3)$会爆炸. 但是没有想到另一个转移方程:定义$f[i][j]$表示每天都有值的$i$天,共消费出总值$j$的方 ...

  7. 【10.11校内测试】【优先队列(反悔贪心)】【莫队】【stl的应用??离线处理+二分】

    上次做过类似的题,原来这道还要简单些?? 上次那道题是每天可以同时买进卖出,所以用两个优先队列,一个存买进,一个存卖出(供反悔的队列). 这道题实际上用一个就够了???但是不好理解!! 所以我还是用了 ...

  8. 【10.7校内测试】【队列滑窗】【2-sat】【贪心+栈二分+线段树(noip模拟好题)】【生日祭!】

    比较好想的一道题,直接用队列滑窗,因为扫一遍往队列里加东西时,改变的只有一个值,开桶储存好就行了! #include<bits/stdc++.h> using namespace std; ...

  9. 【10.6校内测试】【小模拟】【hash+线段树维护覆盖序列】

    一开始看到题就果断跳到T2了!!没想到T2才是个大坑,浪费了两个小时QAQ!! 就是一道小模拟,它怎么说就怎么走就好了! 为什么要用这么多感叹号!!因为统计答案要边走边统计!!如果每个数据都扫一遍20 ...

随机推荐

  1. win10安装

    1.启动盘制作 首先我们需要登陆“微软中国下载中心”,从中下载一款名为“MediaCreationTool”的工具,利用该工具可以制作Win10安装U盘.直接通过以下地址快速进入“Windows下载中 ...

  2. 深拷贝数组 np.copy

    数组对象自带了浅拷贝和深拷贝的方法,但是一般用深拷贝多一些: 代码如下: >>> a = np.ones((2,2)) >>> b = a >>> ...

  3. go 函数介绍

    1. 定义:有输入.有输出,用来执行一个指定任务的代码块 func functionname([parametername type]) [returntype] { //function body ...

  4. Centos7安装 mysql5.6.29 shell脚本

    有很多可以借鉴的地方,故转载: 创建脚本mysql.sh,直接运行sh mysql.sh !/bin/bash if [ -d /software ] ;then cd /software else ...

  5. Jenkins远程调度Shell命令

    http://blog.csdn.net/fireofjava/article/details/40624353 Jenkins服务器为Win7版本,需要远程调用CentOS服务器上Shell脚本,然 ...

  6. 含有ref out 参数 的方法反射 Emit 与 普通

    反射中很多朋友应该屡屡被带有ref out参数的方法折腾 当使用正常反射一个方法时候: 代码如下调用一个后期绑定方法MakeByRefType 就行了 MemberInfo test = typeof ...

  7. Operfire 安装指南

    http://www.cnblogs.com/hoojo/archive/2012/05/13/2498151.html 本文的英文原文来自 http://www.igniterealtime.org ...

  8. mac 删除垃圾篓中的文件

    1.打开终端输入: sudo rm -rf /Volumes/kaid/.Trashes/ 2.输入本机密码

  9. Golang新起航!(编译安装go)

    别废话,直接上~ linux下安装GO1.8 1.下载go的版本 国内地址源:https://dl.gocn.io/ 在这里选择源码的方式安装,在安装go的时候是需要gcc的,所以你的linux系统需 ...

  10. 分享一个自己写的vue多语言插件smart-vue-i18n

    前言 目前有比较成熟的方案(vue-i18n)了解了下,并且实用了一下感觉对于我在使用的项目来说略显臃肿,功能比较多,所以压缩的会比较大,在移动端不太适合所以自己花一天时间撸了一个vue多语言插件,压 ...