[容斥原理][dp]JZOJ P3056 数字

【问题描述】

一个数字被称为好数字当他满足下列条件:

1. 它有2*n个数位,n是正整数(允许有前导0)

2. 构成它的每个数字都在给定的数字集合S中。

3. 它前n位之和与后n位之和相等或者它奇数位之和与偶数位之和相等

例如对于n=2,S={1,2},合法的好数字有1111,1122,1212,1221,2112,2121,2211,2222这样8种。

已知n,求合法的好数字的个数mod 999983。

Input

第一行一个数n。

接下来一个长度不超过10的字符串,表示给定的数字集合。

Output

一行一个数字表示合法的好数字的个数mod 999983。

Sample Input

2
0987654321

Sample Output

1240

Data Constraint

Hint

对于20%的数据,n≤7。

对于100%的.据,n≤1000,|S|≤10。

题解

  • 显然我们可以问题为:
  • 前n位之和与后n位之和相等的方案数+奇数位之和与偶数位之和相等的方案数-前n位之和与后n位之和相等且奇数位之和与偶数位之和相等的方案数

  • 根据容斥原理可以将最后一个转换为:
  • 前n位奇数位之和=后n位偶数位之和 且 前n位偶数位之和=后n位奇数位之和
  • 那么前两个都很容易求,跑一遍dp,f[i][j]表示i个数和为j的可能的方案数
  • 那么i个数可以为n个奇数,也可以为n个偶数
  • 那么前两个的和就是∑(i=1,i<=n*9)2*f[n][i]*f[n][i] (ans)
  • 定义两个数l1=(n+1)/2,l2=n/2
  • l1为前n个数的奇数个数和后n个数的偶数个数
  • l2为前n个数的偶数个数和后n个数的奇数个数
  • 知道这个后方案数自然很容易求
  • ans1=(ans1+f[l1][i]%mo*f[l1][i])%mo; ans2=(ans2+f[l2][i]%mo*f[l2][i])%mo;
  • 答案为ans-ans1*ans2
  • 注意要取膜

代码

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int mo=999983;
 6 int n,len,a[15];
 7 long long ans1,ans2,sum,f[1005][1005*9];
 8 char s[15];
 9 int main()
10 {
11     scanf("%d",&n);
12     scanf("%s",s+1);
13     len=strlen(s+1);
14     for (int i=1;i<=len;i++) a[i]=s[i]-‘0‘;
15     f[0][0]=1;
16     for (int i=1;i<=n;i++)
17         for (int j=0;j<=i*9;j++)
18             for (int k=1;k<=len;k++)
19                 if (j-a[k]>=0)
20                     f[i][j]=(f[i][j]+f[i-1][j-a[k]])%mo;
21     for (int i=0;i<=n*9;i++) sum=(sum+2*f[n][i]%mo*f[n][i])%mo;
22     int l1=(n+1)/2,l2=n/2;
23     for (int i=0;i<=l1*9;i++) ans1=(ans1+f[l1][i]%mo*f[l1][i])%mo;
24     for (int i=0;i<=l2*9;i++) ans2=(ans2+f[l2][i]%mo*f[l2][i])%mo;
25     printf("%lld",(sum-ans1*ans2%mo+mo)%mo);
26 }

原文地址:https://www.cnblogs.com/Comfortable/p/8562344.html

时间: 2024-10-09 17:29:52

[容斥原理][dp]JZOJ P3056 数字的相关文章

[CF245H] Queries for Number of Palindromes (容斥原理dp计数)

题目链接:http://codeforces.com/problemset/problem/245/H 题目大意:给你一个字符串s,对于每次查询,输入为一个数对(i,j),输出s[i..j]之间回文串的个数. 容斥原理: dp[i][j] = dp[i+1][j]+dp[i][j-1]-dp[i+1][j-1]; if( str[i]==str[j] 并且 str[i+1..j-1]是回文串 ) dp[i][j]++; 代码: 1 #include <cstdio> 2 #include &l

TC SRM498 Div1 1000PT(容斥原理+DP)

[\(Description\)] 网格中每步可以走\((0,\cdots M_x,0\cdots M_y)\)中任意非零向量,有\(K\)种向量不能走,分别是\((r_1,r_1),(r_2,r_2),\cdots , (r_K,r_K)\). \(r_i\)一定是\(10\)的倍数.求从\((0,0)\)走到\((Tx,Ty)\)且走\(R\)步的方案数( \(Tx,Ty,Mx,My\leq 800,R\leq 1600,K\leq 50\)) 无 [\(Input\;Sample\)] 无

【基础练习】【棋盘DP】codevs2193 数字三角形ww题解

转载请注明出处 CSDN ametake版权所有 题目描述 Description 数字三角形必须经过某一个点,使之走的路程和最大 输入描述 Input Description 第1行n,表示n行 第2到n+1行为每个的权值 程序必须经过n div 2,n div 2这个点 输出描述 Output Description 最大值 样例输入 Sample Input 2 1 1 1 样例输出 Sample Output 2 数据范围及提示 Data Size & Hint n <=25 今天听

【DP】组合数字

Password Attacker 题意就是给 M 个关键字,组合成 N 字符长度的结果,每一个关键字都必须在 N 位的字符中出现,有多少种可能结果. 范围 1 ≤ M ≤ N ≤ 100. 举例假设 M = 3(key = 3, 7, 5)  N = 4 位字符长度 结果可以为3577, 3557, 7353, 5735. 下面的结果是不合法的 1357 // 1 没有在key中,不是合法关键字 3355 // 7 是关键字,但是结果中没有出现 357 // 结果必须是一个4位长度 思路1:

bzoj 1042: [HAOI2008]硬币购物【容斥原理+dp】

当然是容斥啦. 用dp预处理出\( f[i] \),表示在\( i \)价格时不考虑限制的方案数,转移方程是\( f[i]+=f[i-c[j]] \),用状压枚举不满足的状态容斥一下即可. #include<iostream> #include<cstdio> using namespace std; const long long N=100005; long long c[10],T,d[10],s,f[N],ans; long long read() { long long

[DP]JZOJ 5907 轻功

Description 题目背景:尊者神高达进入了基三的世界,作为一个 mmorpg 做任务是必不可少的,然而跑地图却令人十分不爽.好在基三可以使用轻功,但是尊者神高达有些手残,他决定用梅花桩练习轻功.题目描述:一共有 n 个木桩,要求从起点(0)开始,经过所有梅花桩,恰好到达终点 n,尊者神高达一共会 k 种门派的轻功,不同门派的轻功经过的梅花桩数不同,花费时间也不同.但是尊者神高达一次只能使用一种轻功,当他使用别的门派的轻功时,需要花费 W 秒切换(开始时可以是任意门派,不需要更换时间).由

[概率期望DP]JZOJ 4212 我想大声告诉你

Description 因为小Y 是知名的白富美,所以自然也有很多的追求者,这一天这些追求者打算进行一次游戏来踢出一些人,小R 自然也参加了.这个游戏有n 个人参加,每一轮随机选出一个还没有出局的人x,接着x 会出局.x 在出局之后剩下的人会受到一次攻击,每一个人在遭到攻击之后会有p 的概率出局.(注意遭到攻击出局的人是不能攻击剩下的人的)在所有人都出局之后,遭受攻击次数等于特定值的人能够成为胜者.所以现在小R 想要知道对于每一个0 <= k < n,自己恰好在遭受k 次攻击之后出局的概率是多

[概率dp] Jzoj P2059 卡牌游戏

题目描述 N个人坐成一圈玩游戏.一开始我们把所有玩家按顺时针从1到N编号.首先第一回合是玩家1作为庄家.每个回合庄家都会随机(即按相等的概率)从卡牌堆里选择一张卡片,假设卡片上的数字为X,则庄家首先把卡片上的数字向所有玩家展示,然后按顺时针从庄家位置数第X个人将被处决即退出游戏.然后卡片将会被放回卡牌堆里并重新洗牌.被处决的人按顺时针的下一个人将会作为下一轮的庄家.那么经过N-1轮后最后只会剩下一个人,即为本次游戏的胜者.现在你预先知道了总共有M张卡片,也知道每张卡片上的数字.现在你需要确定每个

[数学][dp] Jzoj P4236 登山

Description 恶梦是一个登山爱好者,今天他来到了黄山.俗话说的好,不走回头路.所以在黄山,你只能往前走,或者往上走.并且很显然的是,当你走到山脊的时候,你不能够往上走,你只能往前走一步再往上走.抽象一点而言就是,你可以把黄山视为一个N * N格点图,恶梦从(0,0)开始出发,要走到(N,N).当他走到位置(x,y)的时候,它可以往(x + 1,y),或(x,y+1)走.并且当他走到(x,x)的时候,由于他已经处在了山脊上,所以他不能够往(x,x+1)方向上走.当恶梦兴致勃勃准备开始爬山