poj1850组合数学

来源:互联网 发布:java多态的作用 编辑:程序博客网 时间:2024/05/23 02:29

题意:给你一个字符串s,输出s在字典序全排列中的位置(从小到大排列)。
思路:长度为m的字符串有C(26,m),这是显而易见的,从26个字母中挑m个,因为要升序排列,所以只有一种排法,即C(26,m)为个数;这样我们就可以求出长度比字符串s小的字符串有多少个。len为字符串s的长度。
长度相同但排在字符串s前面的有多少个?对于 s 的每一位 s[i] 和左边相邻的 s[i-1],如果s[i] > s[i-1],说明当前位置s[i] 至少
比前一位的 s[i-1] 大。
答案 sum 要加上用比 s[i]大的字母构成长度为 len-1-i 的字符串个数,即 C[26-ch][len-1-i]。ch 从 s[i] 到 s[i-1] + 1。

#include<iostream>#include<algorithm>#include<string>#include<cstring>#include<map>#include<queue>#include<cmath>#include<stack>#include<vector>#include<cstdio>#define MAXN 33000#define INF 0x3f3f3f3f#define lmid l,m,rt<<1#define rmid m+1,r,rt<<1|1#define ls rt<<1#define rs rt<<1|1#define Mod 1000000007#define i64 __int64#define LIMIT_ULL 100000000000000000#define Max(a,b) (a>b)?a:b#define lowbit(x) x&(-x)using namespace std;typedef long long ll;char s[15];int c[30][15];void deal(){     for(int i=0;i<=26;i++)          for(int j=0;j<=min(i,10);j++)     {          if(!j||i==j)              c[i][j]=1;              else c[i][j]=c[i-1][j-1]+c[i-1][j];     }}int main(){     deal();     scanf("%s",s);     int n=strlen(s);     bool flag=false;     for(int i=0;i<n-1;i++)          if(s[i]>=s[i+1])               flag=true;          if(flag)          {               cout<<"0"<<endl;               return 0;          }     ll sum=0;     for(int i=1;i<n;i++)          sum+=c[26][i];     for(int i=0;i<n;i++)  //i为s的指针,对每一个位置枚举 允许选择的字符ch     {          char ch= (!i)?'a':s[i-1]+1;//ch =s[i-1]+1 根据升序规则,当前位置的ch至少要比s前一位置的字符大1          while(ch<=s[i]-1)          //ch<=str[i]-1 根据升序规则,当前位置的ch最多只能比s这个位置实际上的字符小1          {               sum+=c['z'-ch][n-1-i];//'z'-ch : 小于等于ch的字符不允许再被选择,所以当前能够选择的字符总数为'z'-ch               ch++;                     //len-1-i  : ch位置后面(不包括ch)剩下的位数,就是从'z'-ch选择len-1-i个字符          }     }     cout<<++sum<<endl;     // 此前的操作都是寻找比s小的所有字符串的个数,并不包括s本身,因此这里要+1}
原创粉丝点击