jzoj5765 【省选模拟8.5】相互再归的鹅妈妈 (集合划分,斯特林反演)

本文主要是介绍jzoj5765 【省选模拟8.5】相互再归的鹅妈妈 (集合划分,斯特林反演),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这里写图片描述

mk<=5e6m<=5e4 m k <= 5 e 6 , m <= 5 e 4

解法

先考虑可以有相同怎么做:
枚举一个第一个脱离限制的位置,然后用一个脱离限制的数来安排使得异或和为0,其他数可以任意取(要分是否脱离限制确定方案数)。这样可以计算出g(n)表示n个可以相同的数,异或和为0的答案。

斯特林反演式子:
[n=1]=mA    (ai1)!(1)ai1 [ n = 1 ] = ∑ m 的 集 合 划 分 A ∏ ( a i − 1 ) ! ⋅ ( − 1 ) a i − 1

证明非常简单, 右侧是圆周排列加上一个正负1的系数
等式右边也就是

ks(n,k)(1)nk ∑ k s ( n , k ) ⋅ ( − 1 ) n − k
,其中k是所划分的集合个数。
不难得出 s(n)(1)nk s ( n ) ⋅ ( − 1 ) n − k 的生成函数就是 x(x1)(x2)...(xn+1)=xn x ( x − 1 ) ( x − 2 ) . . . ( x − n + 1 ) = x n 下 降
令x=1,那么等式右侧就是 1n=s(n,0)+ 1 n 下 降 = s ( n , 0 ) + 原 式 ,即 =[n=1] 原 式 = [ n = 1 ]
我们要求的就是满足 [ai=1] ∏ [ a i = 1 ] 的 方 案 , 根据这个反演一波即可。

#include <cstdio>
#include <iostream>
#include <cstring>
#define lowbit(x) ((x) & -(x))
using namespace std;
typedef long long ll;const ll mo = 1e9 + 7;
ll n, m, k, len;
char s[50100];
ll a[5000100],suf[5000100],mi[5000100];
ll f[8][2][2],g[8],ans,jc[8],mir[8];
ll q[8],size[8];
void dfs(ll x,ll c) {if (x > n) {memset(size,0,sizeof size);for (ll i = 1; i <= n; i++) size[q[i]]++;ll eve = 0, xs = 1;for (ll i = 1; i <= c; i++) {if (size[i] % 2 == 0) eve++;xs = xs * jc[size[i] - 1] % mo * ((size[i]-1)%2==0?1:-1) % mo;}ll odd = c - eve;(ans += xs * g[odd] % mo * mir[eve]) %= mo;return;}q[x] = c + 1;dfs(x + 1, c + 1);for (ll i = 1; i <= c; i++) {q[x] = i;dfs(x + 1, c);}
}
ll ksm(ll x,ll y) {ll ret = 1;for (; y; y>>=1) {if (y & 1) ret = ret * x % mo;x = x * x % mo;}return ret;
}
int main() {freopen("mothergoose.in","r",stdin);freopen("mothergoose.out","w",stdout);cin>>n>>k;jc[0] = 1;for (ll i = 1; i <= n; i++) jc[i] = jc[i - 1] * i;scanf("%s",s + 1); m = strlen(s + 1);for (ll i = 1; i <= k; i++) for (ll j = 1; j <= m; j++) {a[++len] = s[j] - '0';}ll w = 1; mi[len+1] = 1;for (ll i = len; i; i--, w = w * 2 % mo) {suf[i] = (suf[i+1] + w * a[i]) % mo;mi[i] = w * 2 % mo;}mir[0] = 1;for (ll i = 1; i <= n; i++) mir[i] = mir[i - 1] * suf[1] % mo;ll hasone = 0;for (ll i = 1; i <= len; i++) if (a[i] == 1) {memset(f,0,sizeof f);f[0][0][0] = 1;for (ll j = 1; j <= n; j++) {for (ll z = 0; z < 2; z++) //odd or evenfor (ll e = 0; e < 2; e++) { //has or not(f[j][z^1][e] += f[j-1][z][e] * suf[i+1]) %=mo;(f[j][z][1]   += f[j-1][z][e] * (e == 1 ? mi[i+1] : 1)) %= mo;}if (j%2==0 || !hasone) {(g[j] += f[j][0][1]) %= mo;}}hasone = 1;}g[0] = 1;dfs(1,0); ans = (ans + mo) % mo;cout<<ans * ksm(jc[n], mo - 2) % mo<<endl;
}

这篇关于jzoj5765 【省选模拟8.5】相互再归的鹅妈妈 (集合划分,斯特林反演)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/721302

相关文章

基于Redis有序集合实现滑动窗口限流的步骤

《基于Redis有序集合实现滑动窗口限流的步骤》滑动窗口算法是一种基于时间窗口的限流算法,通过动态地滑动窗口,可以动态调整限流的速率,Redis有序集合可以用来实现滑动窗口限流,本文介绍基于Redis... 滑动窗口算法是一种基于时间窗口的限流算法,它将时间划分为若干个固定大小的窗口,每个窗口内记录了该时间

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

usaco 1.2 Transformations(模拟)

我的做法就是一个一个情况枚举出来 注意计算公式: ( 变换后的矩阵记为C) 顺时针旋转90°:C[i] [j]=A[n-j-1] [i] (旋转180°和270° 可以多转几个九十度来推) 对称:C[i] [n-j-1]=A[i] [j] 代码有点长 。。。 /*ID: who jayLANG: C++TASK: transform*/#include<

uva 11178 计算集合模板题

题意: 求三角形行三个角三等分点射线交出的内三角形坐标。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <

poj 2104 and hdu 2665 划分树模板入门题

题意: 给一个数组n(1e5)个数,给一个范围(fr, to, k),求这个范围中第k大的数。 解析: 划分树入门。 bing神的模板。 坑爹的地方是把-l 看成了-1........ 一直re。 代码: poj 2104: #include <iostream>#include <cstdio>#include <cstdlib>#include <al

hdu4431麻将模拟

给13张牌。问增加哪些牌可以胡牌。 胡牌有以下几种情况: 1、一个对子 + 4组 3个相同的牌或者顺子。 2、7个不同的对子。 3、13幺 贪心的思想: 对于某张牌>=3个,先减去3个相同,再组合顺子。 import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOExcepti

Thread如何划分为Warp?

1 .Thread如何划分为Warp? https://jielahou.com/code/cuda/thread-to-warp.html  Thread Index和Thread ID之间有什么关系呢?(线程架构参考这里:CUDA C++ Programming Guide (nvidia.com)open in new window) 1维的Thread Index,其Thread

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点

hdu6053 TrickGCD 莫比乌斯反演

TrickGCD Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Problem Description You are given an array  A  , and Zhu wants to know there are how many d

每日一题|牛客竞赛|四舍五入|字符串+贪心+模拟

每日一题|四舍五入 四舍五入 心有猛虎,细嗅蔷薇。你好朋友,这里是锅巴的C\C++学习笔记,常言道,不积跬步无以至千里,希望有朝一日我们积累的滴水可以击穿顽石。 四舍五入 题目: 牛牛发明了一种新的四舍五入应用于整数,对个位四舍五入,规则如下 12345->12350 12399->12400 输入描述: 输入一个整数n(0<=n<=109 ) 输出描述: 输出一个整数