zoj 3841 Cards
题意:给你52张牌,已知一个牌的序列,然后利用剩余的牌,能排成多少个序列,这个序列比已知的序列字典序小。
思路:从左到右尽可能放比已知序列相应位置小,找不到就放一样,然后求组合数就可以。多重集排列定理:令s时一个多重集,有k个不同类型的元素,各元素的重数分别为n1,n2......nk,令s的大小为n=n1+n2+......nk,则s的排列数为 n!/(n1!*n2!.....nk!);
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <map> 5 #define ll long long 6 #define maxn 100010 7 using namespace std; 8 const int mod=1000000007; 9 10 char str[maxn]; 11 int num[maxn]; 12 ll f[maxn]; 13 map<char,int>q; 14 15 void inti() 16 { 17 f[0]=1; 18 for(int i=1; i<=50; i++) 19 f[i]=(f[i-1]*i)%mod; 20 q['A']=1; 21 for(int i=2; i<=9; i++) 22 q['0'+i]=i; 23 q['1']=10; 24 q['J']=11; 25 q['Q']=12; 26 q['K']=13; 27 } 28 29 ll mult_mod(ll a,ll b,ll c) 30 { 31 a%=c; 32 b%=c; 33 ll ret=0; 34 ll tmp=a; 35 while(b) 36 { 37 if(b&1) 38 { 39 ret+=tmp; 40 if(ret>c) ret-=c; 41 } 42 tmp<<=1; 43 if(tmp>c) tmp-=c; 44 b>>=1; 45 } 46 return ret; 47 } 48 49 ll pow_mod(ll a,ll n) 50 { 51 ll ret=1; 52 ll temp=a%mod; 53 while(n) 54 { 55 if(n&1) 56 { 57 ret=(ret*temp)%mod; 58 } 59 temp=(temp*temp)%mod; 60 n>>=1; 61 } 62 return ret; 63 } 64 int main() 65 { 66 inti(); 67 while(scanf("%s",str)!=EOF) 68 { 69 int k=strlen(str); 70 for(int i=1; i<=13; i++) 71 { 72 num[i]=4; 73 } 74 int cnt=52; 75 for(int i=0; i<k; i++) 76 { 77 num[q[str[i]]]--; 78 cnt--; 79 if(str[i]=='1') i++; 80 } 81 ll ans=0; 82 int m=cnt; 83 bool flag=false; 84 for(int i=0; i<k; i++) 85 { 86 if(cnt==0) break; 87 for(int j=1; j<=13; j++) 88 { 89 if(num[j]>0&&j<q[str[i]]) 90 { 91 ll x=f[cnt-1]; 92 ll y=1; 93 for(int c=1; c<=13; c++) 94 { 95 if(c==j) 96 { 97 y=(y*f[num[c]-1])%mod; 98 continue; 99 } 100 y=(y*f[num[c]])%mod; 101 } 102 x=(x*pow_mod(y,mod-2))%mod; 103 ans=(ans+x)%mod; 104 } 105 } 106 if(num[q[str[i]]]==0) 107 { 108 flag=true; 109 break; 110 } 111 num[q[str[i]]]--; 112 cnt--; 113 if(str[i]=='1') i++; 114 } 115 if(!flag&&m<52-m) 116 ans=(ans+1)%mod; 117 printf("%lld\n",ans); 118 } 119 return 0; 120 }