IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【luogu CF838C】Future Failure(博弈论)(子集卷积) -> 正文阅读

[数据结构与算法]【luogu CF838C】Future Failure(博弈论)(子集卷积)

Future Failure

题目链接:luogu CF838C

题目大意

两个人对着一个字符串博弈,每次可以重新排列这个字符串或者删去一个字符。然后每次得到的字符串要是之前没有出现过的,谁无法操作谁就输了。
然后问你长度为 n 的字符串,只能用 k 种字符,有多少个串先手必胜。

思路

首先我们博弈一下,会发现一个状态能赢要么是它拿走一个存在一个子串能赢,要么就是它这个串的排列方式是偶数。

那考虑那排列方式列出来:
n ! a 1 ! a 2 ! a 3 ! . . . a k ! \dfrac{n!}{a_1!a_2!a_3!...a_k!} a1?!a2?!a3?!...ak?!n!? a i a_i ai? 表示第 i i i 个字符的出现次数)
那你考虑删了一个数会改变多少如果删的是第 i i i 个字符,那就是乘上 a i n \dfrac{a_i}{n} nai??

如果 n n n 是奇数,必定有一个 a i a_i ai? 也是奇数,那你可以删使得奇偶不变。

然后会发现 n n n 是奇数直接必胜,因为如果删了能赢就删,否则就可以不停的排,那后手也一定不能删,也只能排,那会发现如果是不能删的情况一定是偶数中排列方式的。
(可以通过上面那个奇偶不变得到)

那如果是偶数就不能让自己走到奇数,所以就是只用它自己的排列方式是偶数。
那我们接下来就是考虑统计这个偶数的,发现不好统计,我们考虑统计奇数的,就是 n ! n! n! 质因数分解的每个 2 2 2 都可以跟下面的 2 2 2 对应。
那考虑统计 2 2 2 质因子的个数,先考虑一个阶乘怎么求。
n ! → ∑ i ? n 2 i ? n!\rightarrow \sum\limits_{i}\left\lfloor\dfrac{n}{2^i}\right\rfloor n!i??2in??

∑ i ? n 2 i ? = ∑ x = 1 k ∑ i ? a x 2 i ? \sum\limits_{i}\left\lfloor\dfrac{n}{2^i}\right\rfloor=\sum\limits_{x=1}^k\sum\limits_{i}\left\lfloor\dfrac{a_x}{2^i}\right\rfloor i??2in??=x=1k?i??2iax???

然后我们考虑不停分解 x x x 出来,因为上的数量肯定比下面的多,那我们就把这个情况看到每个 2 i 2^i 2i 中,这都应该是要满足的,所以它们每一位应该都是一样的:
? i ∈ N , ? n 2 i ? = ∑ i ? a x 2 i ? \forall i\in N,\left\lfloor\dfrac{n}{2^i}\right\rfloor=\sum\limits_{i}\left\lfloor\dfrac{a_x}{2^i}\right\rfloor ?iN,?2in??=i??2iax???
那你就考虑这个是什么鬼,那我们会发现这个其实跟二进制有关,就是所有 a x a_x ax? 加在一起不能有进位。

那这个其实我们不难想到一个东西就是把 n n n 的二进制拆成若干份,每个 x x x 贡献是 1 x ! \dfrac{1}{x!} x!1?,然后每个的贡献乘起来,最后另外乘上 n ! n! n!
然后你这个乘你可以用循环卷积来做,就 k k k 个字符依次加入然后 FWT 一下。
然后这样还是太慢所以可以 k k k 这个地方快速幂一下。

代码

#include<cstdio>
#define ll long long

using namespace std;

const int N = 1 << 19;
int n, k, mo, jc[N], inv[N], num1[N];
int f[20][N], g[20][N];

int jia(int x, int y) {return x + y >= mo ? x + y - mo : x + y;}
int jian(int x, int y) {return x < y ? x - y + mo : x - y;}
int cheng(int x, int y) {return 1ll * x * y % mo;}

int ksm(int x, int y) {
	int re = 1;
	while (y) {
		if (y & 1) re = cheng(re, x);
		x = cheng(x, x); y >>= 1; 
	}
	return re;
}

void Init() {
	jc[0] = 1; for (int i = 1; i < N; i++) jc[i] = cheng(jc[i - 1], i);
	inv[0] = inv[1] = 1; for (int i = 2; i < N; i++) inv[i] = cheng(inv[mo % i], (mo - mo / i));
	for (int i = 1; i < N; i++) inv[i] = cheng(inv[i - 1], inv[i]);
	for (int i = 1; i < N; i++) num1[i] = num1[i ^ (i & (-i))] + 1;
}

void FWT(int *f, int limit, int op) {
	for (int mid = 1; mid < limit; mid <<= 1) {
		for (int R = mid << 1, j = 0; j < limit; j += R) {
			for (int k = 0; k < mid; k++) {
				ll x = f[j | k], y = f[j | mid | k];
				f[j | k] = x; f[j | mid | k] = jia(cheng(x, op), y);
			}
		}
	}
}

int work(int n, int k) {
	int m = 1; while (m <= n) m <<= 1;
	f[0][0] = 1; for (int i = 0; i <= n; i++) g[num1[i]][i] = inv[i];
	for (int i = 0; i < num1[n]; i++) FWT(g[i], m, 1);
	FWT(f[0], m, 1);
	for (int kk = k; kk; kk >>= 1) {
		if (kk & 1) {
			for (int i = num1[n]; i >= 0; i--) {
				for (int j = 0; j < m; j++)
					f[i][j] = cheng(f[i][j], g[0][j]);
				for (int j = 0; j < i; j++)
					for (int k = 0; k < m; k++) {
						f[i][k] = jia(f[i][k], cheng(f[j][k], g[i - j][k]));
					}
			}
		}
		for (int i = num1[n]; i >= 0; i--) {
			for (int j = 0; j < m; j++)
				g[i][j] = cheng((i ? 2 : 1), cheng(g[i][j], g[0][j]));
			for (int j = 1; j < i; j++)
				for (int k = 0; k < m; k++) {
					g[i][k] = jia(g[i][k], cheng(g[j][k], g[i - j][k]));
				}
		}
	}
	FWT(f[num1[n]], m, mo - 1);
	return cheng(f[num1[n]][n], jc[n]);
}

int main() {
	scanf("%d %d %d", &n, &k, &mo);
	
	if (n & 1) {
		printf("%d", ksm(k, n)); return 0;
	}
	
	Init();
	printf("%d", jian(ksm(k, n), work(n, k)));
	
	return 0;
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-04-04 12:36:03  更:2022-04-04 12:39:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 9:58:27-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码