HDU 3398 String (组合数学+数论思维)*
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3398
题目大意
一个串中恰好有n个1和m个0,
问满足这样条件的字符串有多少种,
其任意前缀中1的数量不少于0的数量。
题目分析
组合问题,画出n*m的二维矩阵,
构造一个串对应着从(0,0)到(n,m)的一个路径,
而任意前缀中1的数量不少于0,意味着路径不与y=x+1这条直线
相交,详见图片。
然后就是答案的求解过程了,普通的对每个数质因分解可能会爆,
不妨看看对于特定的因子阶乘数中出现的次数,这样就可以简化成logn时间了。
时间复杂度:O(nlogn)。
#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=20100501;
const ll maxn=2e6+5;
const int ub=1e6;
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;}
int gcd(int x,int y){return y?gcd(y,x%y):x;}
/*
题目大意:
一个串中恰好有n个1和m个0,
问满足这样条件的字符串有多少种,
其任意前缀中1的数量不少于0的数量。
组合问题,画出n*m的二维矩阵,
构造一个串对应着从(0,0)到(n,m)的一个路径,
而任意前缀中1的数量不少于0,意味着路径不与y=x+1这条直线
相交,详见图片。
然后就是答案的求解过程了,普通的对每个数质因分解可能会爆,
不妨看看对于特定的因子阶乘数中出现的次数,这样就可以简化成logn时间了。
时间复杂度:O(nlogn)。题目分析:
*/
int prim[maxn],tot=0,pos[maxn];
bool vis[maxn];
void sieve(){
mst(vis,false);
for(int i=2;i<maxn;i++){
if(vis[i]==0) prim[tot++]=i;
for(int j=0;j<tot;j++){
if(1LL*i*prim[j]>=maxn) break;
int tmp=i*prim[j];vis[tmp]=true;
if(i%prim[j]==0) break;
}
}
}
void divid(int x,int v){
for(int i=0;i<tot&&prim[i]<=x;i++){
int tmp=x;
while(tmp){
tmp/=prim[i];
pos[i]+=v*tmp;
}
}
}
void solve(int x){
for(int i=0;i<tot&&x!=1;i++)if(x%prim[i]==0){
while(x%prim[i]==0){
x/=prim[i];
pos[i]++;
}
}
}
int n,m;
int main(){
sieve();///筛法
int t;scanf("%d",&t);
while(t--){
mst(pos,0);///
scanf("%d%d",&n,&m);
divid(n+1,-1),divid(m,-1),divid(n+m,1);
solve(n+1-m);
ll ans=1;
rep(i,0,tot) if(pos[i])
ans=ans*powmod(1LL*prim[i],1LL*pos[i])%mod;
printf("%lld\n",ans);
}
return 0;
}