文章目录
D. Destroy the Colony
题意:
给定一个长度为偶数的字符串,将字符串分成长度相等的两个字符串,要求同一种字符必须在同一个字符串里面,给出Q个查询,每次要去第x个字符和第y个字符必须在同一组内
分析
可以明显看出这是一个背包问题,背包的容量是n/2,先不考虑指定的字符,那么总共有多少种方法?
dp[52][n/2]∗fac[n/2]∗fac[n/2]/(fac[num[1]]∗fac[num[2]...)
注: num[x] 代表类型x有多少个,fac[i] 代表i的阶乘
加上条件限制之后就可以去掉这两个的方案
dp[j]=dp[j]−dp[j−num[x]]
dp[j]=dp[j]−dp[j−num[y]]
代码参考(代码比较矬)
#include <bits/stdc++.h>
#define mem(ar,num) memset(ar,num,sizeof(ar))
#define me(ar) memset(ar,0,sizeof(ar))
#define lowbit(x) (x&(-x))
#define Pb push_back
#define FI first
#define SE second
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define IOS ios::sync_with_stdio(false)
#define DEBUG cout<<endl<<"DEBUG"<<endl;
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int prime = 999983;
const int INF = 0x7FFFFFFF;
const LL INFF =0x7FFFFFFFFFFFFFFF;
const double pi = acos(-1.0);
const double inf = 1e18;
const double eps = 1e-6;
const int mod = 1e9 + 7;
LL qpow(LL a,LL b){LL s=1;while(b>0){if(b&1)s=s*a%mod;a=a*a%mod;b>>=1;}return s;}
LL gcd(LL a,LL b) {return b?gcd(b,a%b):a;}
int dr[2][4] = {1,-1,0,0,0,0,-1,1};
typedef pair<int,int> P;
const int maxn = 1e5+10;
char ar[maxn];
int num[256];
// ans[m?]
const int maxm = 60;
int ans[maxm][maxm];
int fac[maxn],invfac[maxn],dp[maxn],f[maxn];
void init(int n){
fac[0] = fac[1] = 1;
for(int i = 2;i <= n; ++i)
fac[i] = 1ll*fac[i-1]*i%mod;
invfac[n] = qpow(fac[n],mod-2);
for(int i = n-1;i >= 1; --i)
invfac[i] = 1ll*invfac[i+1]*(i+1)%mod;
}
int id(char c){
if(c < 'a')
return c-'A'+1;
return c-'a'+26+1;
}
inline int add(int a){
if(a >= mod) a -= mod;
return a;
}
int main(void)
{
init(maxn-1);
scanf("%s",ar+1);int n = strlen(ar+1);
for(int i = 1;i <= n; ++i)
num[id(ar[i])]++;
int v = 1ll*fac[n/2]*fac[n/2]%mod;
for(int i = 1;i <= 52; ++i)
if(num[i])
v = 1ll*v*invfac[num[i]]%mod;
dp[0] = 1;
for(int i = 1;i <= 52; ++i)
if(num[i])
for(int j = n/2;j >= num[i]; --j)
dp[j] = (dp[j-num[i]]+dp[j])%mod;
for(int i = 1;i <= 52; ++i){
for(int j = 1;j <= 52; ++j){
if(num[i] == 0||num[j] == 0) continue;
int x = i,y = j;
rep(k,0,n/2+1) f[k] = dp[k];
rep(k,num[x],n/2+1) f[k] = add((f[k]-f[k-num[x]] + mod));
if(x != y)
rep(k,num[y],n/2+1) f[k] = add((f[k]-f[k-num[y]]+mod));
ans[x][y] = 1ll*2*v*f[n/2]%mod;
}
}
int Q;cin>>Q;
while(Q--){
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",ans[id(ar[x])][id(ar[y])]);
}
return 0;
}
1.删除三个字符
2. morse code