当前位置: 代码迷 >> 综合 >> CodeCraft-19 and Codeforces Round #537 (Div. 2) D. Destroy the Colony(组合数学+退背包)
  详细解决方案

CodeCraft-19 and Codeforces Round #537 (Div. 2) D. Destroy the Colony(组合数学+退背包)

热度:105   发布时间:2023-11-15 12:28:55.0

题目链接:http://codeforces.com/contest/1111/problem/D

题目大意:

这道题题目意思比较模糊。

给定一个字符串,不同字符代表不同种类的坏人,

现在给定若干个询问,每个询问给两个下标,

要求把给定位置上的两个(或一个)类型的人放到同一边,

并且其他相同种类的人均在同一边的方案数。

题目分析: 

首先考虑不加限制的计数方案,

就是说不考虑和种类在同一边的情况。

如果单独考虑一边,把半边的情况选好了那另一半的情况也是类似,

但是半边的计数方案和具体的选择种类有关系,就算我们通过组合公式

来执行背包计数也无法把两边的计数方案结合到一起去,那么不妨两边一块考虑,

分母消去所有种类的重复度,分子是两边长度阶乘的贡献:,

对这部分只要处理常用的阶乘逆元即可。

下面先算总体贡献:.这部分用普通的背包计数即可。

如何把两个询问下标考虑进去需要利用到退背包的知识,即在集合S中不考虑第i种物品的情况下

对目标值所产生的计数,设为,那么有如下递推方程:

对于两个查询下标种类一样的情况其实本质差不多,少退一次背包而已。

时间复杂度:O(52*52*N)。

 

#include<bits/stdc++.h>
using namespace std;#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define ll long long#define lrt int l,int r,int rt
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define root l,r,rt
#define mst(a,b) memset((a),(b),sizeof(a))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
const int mod=1e9+7;
const int maxn=1e5+5;
const int ub=1e6;
const double inf=1e-4;
ll powmod(ll x,ll y){ll t; for(t=1;y;y>>=1,x=x*x%mod) if(y&1) t=t*x%mod; return t;}
ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
/*
题目大意:*/
char s[maxn];
int len,cnt[52],q,x,y;
ll dp[maxn],g[maxn],ans[52][52];
int idx(char c){if(c<='z'&&c>='a') return c-'a';return 26+c-'A';
}
ll fac[maxn],inv[maxn];
void init(){fac[0]=1;rep(i,1,maxn) fac[i]=fac[i-1]*i%mod;inv[maxn-1]=powmod(fac[maxn-1],mod-2);for(int i=maxn-2;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
}
ll C(ll p,ll q){return fac[p]*inv[q]%mod*inv[p-q]%mod;
}
void Back(int x){rep(k,0,x) g[k]=dp[k];rep(k,x,len/2+1) g[k]=(dp[k]-g[k-x]+mod)%mod;
}
int main(){init();scanf("%s",s);len=strlen(s);///rep(i,0,len) cnt[idx(s[i])]++;mst(dp,0),mst(g,0),dp[0]=1;rep(i,0,52) if(cnt[i]) for(int j=len/2;j>=cnt[i];j--)(dp[j]+=dp[j-cnt[i]])%=mod;///背包DP计数mst(ans,0);///rep(i,0,52) rep(j,i,52){Back(cnt[i]);///退背包过程if(i!=j) rep(k,cnt[j],len/2+1)g[k]=(g[k]-g[k-cnt[j]]+mod)%mod;ans[i][j]=g[len/2];}ll xishu=fac[len/2]*fac[len/2]%mod;rep(i,0,52) xishu=xishu*inv[cnt[i]]%mod;cin>>q;rep(i,0,q){cin>>x>>y;x=idx(s[x-1]),y=idx(s[y-1]);ll ret=max(ans[x][y],ans[y][x]);ret=ret*2%mod*xishu%mod;cout<<ret<<endl;}return 0;
}

 

  相关解决方案