D. Destroy the Colony

题意:

给定一个长度为偶数的字符串,将字符串分成长度相等的两个字符串,要求同一种字符必须在同一个字符串里面,给出Q个查询,每次要去第x个字符和第y个字符必须在同一组内

分析

可以明显看出这是一个背包问题,背包的容量是n/2,先不考虑指定的字符,那么总共有多少种方法?

d p [ 52 ] [ n / 2 ] f a c [ n / 2 ] f a c [ n / 2 ] / ( f a c [ n u m [ 1 ] ] f a c [ n u m [ 2 ] . . . ) dp[52][n/2] * fac[n/2]*fac[n/2]/(fac[num[1]]*fac[num[2]...) dp[52][n/2]fac[n/2]fac[n/2]/(fac[num[1]]fac[num[2]...)
注: num[x] 代表类型x有多少个,fac[i] 代表i的阶乘
加上条件限制之后就可以去掉这两个的方案
d p [ j ] = d p [ j ] d p [ j n u m [ x ] ] dp[j] = dp[j] - dp[j-num[x]] dp[j]=dp[j]dp[jnum[x]]
d p [ j ] = d p [ j ] d p [ j n u m [ y ] ] dp[j] = dp[j] - dp[j-num[y]] dp[j]=dp[j]dp[jnum[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