D. Destroy the Colony

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值