codeforces 895D - String Mark
http://codeforces.com/contest/895/problem/D
题意:给你二个等长 ( len <= 1e6 ) 字符串 a, b, 并且 a 的 字典序比 b 小, 让你构造字符串 c , 问 c 的情况有多少种 (mod 1e9+7)
要求:1. c 的字母组成 和 a 一样
2. a 的字典序比 c 小
3. c 的字典序比 b 小
题解:由于题目要求的是 c 的组合有多少种,那可以先求出 c 的排列,再除以每个字母个数的阶乘积即可
求比字符串 b 字典序小的排列个数,
dfs( id, b) 表示 c[ 1~(id-1) ] = b [ 1~(id-1) ] 情况下,比 b 字典序小的有多少
那么 若 c[id] = b[id] 取和字符 b[id] 相等的一个,问题就转化成 dfs(id+1, b)
若 c[id] < b[id] 取比字符 b[id] 小的一个,剩下的字符全排列
若 c[id] > b[id] 则 c 的字典序比 b 的大,舍去
long long dfs(int id, string s) //递归爆栈 MLE { if( id >= s.size() ) return 0; long long ans = 0; if(num[s[id]-'a']) { --num[s[id]-'a']; ans = dfs(id+1, s) * (++num[s[id]-'a']) % mod; } long long k = sum(s[id]-'a'); return (ans + k * A[ s.size()-id-1 ] % mod) % mod; }
很难受的是递归调用爆栈了,于是模拟递归写了下
long long sta[MAXN]; long long dfs(string s) // 模拟栈 { memset(sta, 0x00, sizeof(sta)); int i = 0; while( i < s.size() && num[s[i]-'a'] ) --num[s[i]-'a'], ++i; if( i < s.size() ) { long long k = sum(s[i]-'a'); sta[i] = (sta[i] + k * A[ s.size()-i-1 ] % mod) % mod; } while( --i >= 0 ) { sta[i] = (++num[s[i]-'a']) * sta[i+1] % mod; long long k = sum(s[i]-'a'); sta[i] = (sta[i] + k * A[ s.size()-i-1 ] % mod) % mod; } return sta[0]; }
AC代码
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #define mod 1000000007 using namespace std; const int MAXN = 1000000+10; long long A[MAXN]; int num[26]; void init() { A[0] = 1; for(int i = 1; i < MAXN; ++i) A[i] = A[i-1]*i%mod; memset(num, 0x00, sizeof(num)); } int sum(int k) { int ans = 0; for(int i = 0; i < k; ++i) ans += num[i]; return ans; } long long dfs(int id, string s) //递归爆栈 MLE { if( id >= s.size() ) return 0; long long ans = 0; if(num[s[id]-'a']) { --num[s[id]-'a']; ans = dfs(id+1, s) * (++num[s[id]-'a']) % mod; } long long k = sum(s[id]-'a'); return (ans + k * A[ s.size()-id-1 ] % mod) % mod; } long long sta[MAXN]; long long dfs(string s) // 模拟栈 { memset(sta, 0x00, sizeof(sta)); int i = 0; while( i < s.size() && num[s[i]-'a'] ) --num[s[i]-'a'], ++i; if( i < s.size() ) { long long k = sum(s[i]-'a'); sta[i] = (sta[i] + k * A[ s.size()-i-1 ] % mod) % mod; } while( --i >= 0 ) { sta[i] = (++num[s[i]-'a']) * sta[i+1] % mod; long long k = sum(s[i]-'a'); sta[i] = (sta[i] + k * A[ s.size()-i-1 ] % mod) % mod; } return sta[0]; } long long silimar() { long long ans = 1; for(int i = 0; i < 26; ++i) ans = ans * A[num[i]] % mod; return ans; } long long ex(long long x, long long n) //return x^n { long long sum = 1; x %= mod; while(n) { if( n&1 ) sum *= x, sum %= mod; n /= 2; x *= x; x %= mod; } return sum; } int main (void) { init(); string a, b, c; cin >> a >> b; for(int i = 0; i < a.size(); ++i) ++num[ a[i]-'a' ]; // long long ans = dfs(0, b) - dfs(0, a); //递归爆栈 MLE long long ans = dfs( b ) - dfs( a ); // 模拟栈 long long k = silimar(); ans = ans * ex(k, mod-2) % mod; cout << ( ans - 1 + mod ) % mod; return 0; }