CodeCraft-19 and Codeforces Round #537 (Div. 2) D 多重排列 + 反向01背包 + 离线处理
https://codeforces.com/contest/1111/problem/D
多重排列 + 反向01背包
题意:
给你一个字符串(n<=1e5,n为偶数),有q个询问,每次询问两个位置x和y,问将和x,y相同的所有字符移到前半段或者后半段,并且剩下的所有字符都要在同一半段的方案数,字符是大写小写字母
题解:
- 首先不考虑x和y位置,假设前半段的排列数为\((n/2)!/(cnt[x_1]!*...*cnt[x_n]!)\),后半段的排列为\((n/2)!/(cnt[y_1]!*...*cnt[y_n]!)\),那么总的排列数就是\((n/2)!/(cnt[1]!*...*cnt[n]!)\) 多重排列公式
 - 对于每个字符,有全部取或者全部不取两种,因此可以用一个容量为n/2的01背包求出总的分配方案数
 - 因为只有52个字符,所以可以预处理出任意两个字符的分配方案数
 - 答案就是 \(2*总排列数*分配方案数\)
 
处理
- 累加方案数的时候反向处理,减去方案数的时候正向处理(常见)
 
即正常累加01背包的时候都是反着扫,但是用总方案减去非法方案的时候需要正着扫
- 附上线性逆元,阶乘,逆元阶乘打表板子
 
代码
#include<bits/stdc++.h>
#define P 1000000007
#define M 100005
#define ll long long
using namespace std;
ll f[60][60],c[60],inv[M],F[M],tp[M],dp[M],ans,Finv[M];
int i,j,x,y,q,n,l,r;
string s;
void init(){
	cin>>s>>q;n=s.size();
	F[0]=Finv[0]=inv[0]=1;
	F[1]=Finv[1]=inv[1]=1;
	for(i=2;i<M;i++){
		inv[i]=inv[P%i]*(P-P/i)%P;
		Finv[i]=Finv[i-1]*inv[i]%P;
		F[i]=F[i-1]*i%P;
	}
	for(i=0;i<n;i++){
		if(s[i]>='a'&&s[i]<='z')c[s[i]-'a'+1]++;
		else c[s[i]-'A'+27]++;
	}
	ans=F[n/2]*F[n/2]%P;
	for(i=1;i<=52;i++)
		if(c[i])ans=ans*Finv[c[i]]%P;
	dp[0]=1;
	for(i=1;i<=52;i++)if(c[i])
		for(j=n/2;j>=c[i];j--)dp[j]=(dp[j]+dp[j-c[i]])%P;
	for(x=1;x<=52;x++){
		for(y=1;y<=52;y++){
			for(i=0;i<=n/2;i++)tp[i]=dp[i];
			for(i=c[x];i<=n/2;i++)tp[i]=(tp[i]-tp[i-c[x]]+P)%P;
			if(x!=y)for(i=c[y];i<=n/2;i++)tp[i]=(tp[i]-tp[i-c[y]]+P)%P;
			f[x][y]=tp[n/2];
		}
	}
}
int main(){
	init();
	while(q--){
		scanf("%d%d",&l,&r);
		l--;r--;
		if(s[l]>='a'&&s[l]<='z')l=s[l]-'a'+1;
		else l=s[l]-'A'+27;
		if(s[r]>='a'&&s[r]<='z')r=s[r]-'a'+1;
		else r=s[r]-'A'+27;
		printf("%lld\n",2ll*ans%P*f[l][r]%P);
	}
}
												
											CodeCraft-19 and Codeforces Round #537 (Div. 2) D 多重排列 + 反向01背包 + 离线处理的更多相关文章
- CodeCraft-19 and Codeforces Round #537 Div. 2
		
D:即有不超过52种物品,求容量为n/2的有序01背包方案数.容易想到设f[i][j]为前i种物品已用容量为j的方案数,有f[i][j]=f[i-1][j-a[i]]*C(n/2-j+a[i],a[i ...
 - CodeCraft-19 and Codeforces Round #537 (Div. 2) E 虚树 + 树形dp(新坑)
		
https://codeforces.com/contest/1111/problem/E 题意 一颗有n个点的树,有q个询问,每次从树挑出k个点,问将这k个点分成m组,需要保证在同一组中不存在一个点 ...
 - CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解
		
传送门 D. Destroy the Colony 首先明确题意:除了规定的两种(或一种)字母要在同侧以外,其他字母也必须在同侧. 发现当每种字母在左/右边确定之后,方案数就确定了,就是分组的方案数乘 ...
 - CodeCraft-19 and Codeforces Round #537 (Div. 2)  C. Creative Snap 分治
		
Thanos wants to destroy the avengers base, but he needs to destroy the avengers along with their bas ...
 - 【CodeCraft-19 and Codeforces Round #537 (Div. 2) C】Creative Snap
		
[链接] 我是链接,点我呀:) [题意] 横坐标1..2^n对应着2^n个复仇者的基地,上面有k个复仇者(位置依次给出). 你是灭霸你要用以下方法消灭这k个复仇者: 一开始你获取整个区间[1..2^n ...
 - Codeforces Round #532 (Div. 2) F 线性基(新坑) + 贪心 + 离线处理
		
https://codeforces.com/contest/1100/problem/F 题意 一个有n个数组c[],q次询问,每次询问一个区间的子集最大异或和 题解 单问区间子集最大异或和,线性基 ...
 - Codeforces Round #207 (Div. 1)    A. Knight Tournament  (线段树离线)
		
题目:http://codeforces.com/problemset/problem/356/A 题意:首先给你n,m,代表有n个人还有m次描述,下面m行,每行l,r,x,代表l到r这个区间都被x所 ...
 - Codeforces Round #365 (Div. 2) D - Mishka and Interesting sum(离线树状数组)
		
http://codeforces.com/contest/703/problem/D 题意: 给出一行数,有m次查询,每次查询输出区间内出现次数为偶数次的数字的异或和. 思路: 这儿利用一下异或和的 ...
 - Codeforces Round #214 (Div. 2) C. Dima and Salad (背包变形)
		
C. Dima and Salad time limit per test 1 second memory limit per test 256 megabytes input standard in ...
 
随机推荐
- 关于vs2010开发的ASP项目部署到XPSP2系统上出现找不到Reportviewer.XX.文件的解决方案
			
尝试方法如下: 1.将webform.dll.winform.dll.common.dll三个引用直接复制到服务器的Bin目录,未解决问题,提示无法正确加载,程序及已关闭等. 2.SQLSysClrT ...
 - 项目总结13:Jav文件压缩-InputStream转化为base64-Base64解码并生成图片
			
Jav文件压缩-InputStream转化为base64-Base64解码并生成图片 直接上源码,解释见文章尾部 package com.hs.common.util.imgecode; import ...
 - java中Date无法获取数据库时分秒的问题
			
数据库使用的字段是timestamp(6),在数据库看的时候明明时分秒是有的,然而通过rs.getDate()获取出来的时候时分秒就没有了,查了一下资料终于解决了,这里有一个重要的知识点,java ...
 - java  线程Thread 技术--创建线程的方式
			
在第一节中,对线程的创建我们通过看文档,得知线程的创建有两种方式进行实现,我们进行第一种方式的创建,通过继承Thread 类 ,并且重写它的run 方法,就可以进行线程的创建,所有的程序执行都放在了r ...
 - delete,truncate 和 delete之间的区别
			
1.首先看下语法定义: drop table_name truncate table_name delete table_name [where column_name = value] 2.各个删除 ...
 - git add 文件夹
			
1. 本地新建好文件夹,在文件夹里新建*.md 2. 切换到文件夹父目录 3. git add 文件夹名 4. git commit 5. git push
 - Django中反向生成models
			
我们在展示django ORM反向生成之前,我们先说一下怎么样正向生成代码. 正向生成,指的是先创建model.py文件,然后通过django内置的编译器,在数据库如mysql中创建出符合model. ...
 - golang 实现延迟消息原理与方法
			
实现延迟消息具体思路我是看的下面这篇文章 https://mp.weixin.qq.com/s/eDMV25YqCPYjxQG-dvqSqQ 实现延迟消息最主要的两个结构: 环形队列:通过golang ...
 - mysql 安装后出现 10061错误
			
#服务器端 提示 The vervice already exists! The current server installed #mysqld 服务没有启动 解决办法 移除原来的mysql服务 ...
 - springBoot整合Quarzt2.3
			
首先,你要配置好springboot的配置(在resources下) 我把其改为application.yml # Tomcat server: tomcat: uri-encoding: UTF-8 ...