TopCoder - 12118
单位根反演,指数生成函数。
题意
给你两个仅包含 a,b,c 字符串 A,B(∣A∣,∣B∣≤11),以及一个长度为 3 的数组分别表示 a→b,b→c,c→a 的代价,和 Maxcost(≤109),问在不超过 Maxcost 将 A 变成 B 的方案数。两种方案视为不同的,当存在一个位置,两个方案改变了不同的位置的字符。
题解
每个位置若 Ai=Bi ,先要花费一定步数使其变到 B 。然后每个位置再可以变三的倍数次。
题意转化为每个位置操作次数为 ci=3k+ai(ai∈{0,1,2},k∈N) 。然后总次数 ∑ici≤N 。且对于一个确定的操作次数序列 ⟨c1,c2,…,cn⟩ 其贡献为 ∏i(ci!)(∑ici)! 。
设 Fj^(x) 表示位置 j 的指数生成函数,[xi]Fj^(x) 即第 j 个位置操作次数为 i 的方案数。
Fj^(x)=i≥0∑(3i+aj)!x3i+aj=i≥0∑[imod3=aj]i!xi=i≥0∑[3∣(i−aj)]i!xi=i≥0∑31k=0∑2ω3k(i−aj)i!xi=31i≥0∑k=0∑2ω3kajω3kii!xi=31k=0∑2ω3kaj1i≥0∑ω3kii!xi
令 G^(x)=∏j=1nFj^(x) ,gi=[xi]G^(x) 答案就等于 ∑i=0Ngi
G^(x)=j=1∏n(31k=0∑2ω3kaj1i≥0∑ω3kii!xi)=3n1j=1∏n(k=0∑2ω3kaj1i≥0∑ω3kii!xi)=3n1j=1∏n(k=0∑2ω3−kajeω3kx)
前面那项是个定值,观察后面这项就是 ∏j=1n(eω30x+ω3−ajeω31x+ω3−2ajeω32x) 可以暴力展开 O(3n),会得到若干 □e□x 的和。然后每项可以这样展开:
p⋅eqx=i=0∑∞i!pqixi
然后对每个 p⋅eqx 对应的指数生成函数求系数前缀和:
i=0∑Npqi=p×q−1qN+1−1
CODE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
| #include <bits/stdc++.h> #define MOD(x) ((x)<mod?(x):((x)%mod)) template<typename _Tp> inline void red(_Tp &x) { x=0;bool fg=0;char ch=getchar(); while(ch<'0'||ch>'9') {if(ch=='-') fg^=1;ch=getchar();} while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(_Tp)(ch^48),ch=getchar(); if(fg) x=-x; } template <typename _Tp,typename... Args>void red(_Tp &t,Args &... args){red(t);red(args...);} using namespace std; typedef long long ll; const ll mod = 1e9+7; const ll sq3 = 82062379; const ll inv3 = 333333336; struct com{ ll x,y; com(ll _x=0,ll _y=0):x(_x),y(_y){} com operator+(const com &t) {return com((x+t.x)%mod,(y+t.y)%mod);} com operator+=(const com &t) {*this=*this+t;return *this;} com operator*(const com &t) {return com(((x*t.x-y*t.y)%mod+mod)%mod,(x*t.y+y*t.x)%mod);} com operator=(const ll &t) {*this=com(t%mod,0);return *this;} }; ostream &operator<<(ostream &out,com a) {return out << "(" << a.x << ", " << a.y <<") ";} class ConversionMachine { private: ll fpow(ll a,ll b) { a%=mod; ll r=1; for(;b;b>>=1,a=MOD(a*a)) if(b&1) r=MOD(r*a); return r; } com inv(com t) { ll q=fpow((t.x*t.x+t.y*t.y)%mod,mod-2); return com(MOD(t.x*q),(mod-(t.y*q)%mod)%mod); } com fpow(com a,ll b) { com r=1; if(b<0) {a=inv(a); b=-b;} for(;b;b>>=1,a=a*a) if(b&1) r=r*a; return r; } ll inv(ll x) {return fpow(x%mod,mod-2);} const com w=com((mod-1)/2,(mod+sq3)/2),iw=com((mod-1)/2,(mod-sq3)/2); com calc(com q,ll k) { if(q.x==1&&q.y==0) return com(k+1,0); return (fpow(q,k+1)+com(mod-1,0))*inv(q+com(mod-1,0)); } public: com f[2][32][32]; int countAll(string A,string B,vector<int> cost,ll maxcost) { int n=A.size(),N=0; vector<int> a(n); com ans=com(1,0); for(int i=0;i<n;++i) { while(A[i]!=B[i]) { maxcost-=cost[A[i]-'a']; A[i]='a'+(A[i]-'a'+1)%3; a[i]++; } N+=a[i]; ans=ans*com(inv3,0); } if(maxcost<0) return 0; N+=maxcost/(cost[0]+cost[1]+cost[2])*3; memset(f,0,sizeof(f)); f[0][0][0]=1; bool V=0; for(int i=0;i<n;++i) { memset(f[V^1],0,sizeof(f[V^1])); for(int j=0;j<=i;++j) { for(int k=0;j+k<=i;++k) { f[V^1][j+1][k]+=f[V][j][k]; f[V^1][j][k+1]+=fpow(w,-a[i])*f[V][j][k]; f[V^1][j][k]+=fpow(w,-2*a[i])*f[V][j][k]; } } V^=1; } com sum; for(int i=0;i<=n;++i) { for(int j=0;i+j<=n;++j) { com q=com(i,0)+com(j,0)*w+com(n-i-j)*iw; sum=sum+f[V][i][j]*calc(q,N); } } ans=ans*sum; return ans.x; } public: void run_test(int Case) { if ((Case == -1) || (Case == 0)) test_case_0(); if ((Case == -1) || (Case == 1)) test_case_1(); if ((Case == -1) || (Case == 2)) test_case_2(); if ((Case == -1) || (Case == 3)) test_case_3(); } private: template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); } void verify_case(int Case, const int &Expected, const int &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } } void test_case_0() { string Arg0 = "a"; string Arg1 = "b"; int Arr2[] = {100,2,3}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 205; int Arg4 = 2; verify_case(0, Arg4, countAll(Arg0, Arg1, Arg2, Arg3)); } void test_case_1() { string Arg0 = "abcba"; string Arg1 = "abcba"; int Arr2[] = {67,23,43}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 0; int Arg4 = 1; verify_case(1, Arg4, countAll(Arg0, Arg1, Arg2, Arg3)); } void test_case_2() { string Arg0 = "cccccccc"; string Arg1 = "aaaaaaaa"; int Arr2[] = {10000000,1,1}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 100; int Arg4 = 40320; verify_case(2, Arg4, countAll(Arg0, Arg1, Arg2, Arg3)); } void test_case_3() { string Arg0 = "aa"; string Arg1 = "cc"; int Arr2[] = {1,10,100}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 1787; int Arg4 = 123611681; verify_case(3, Arg4, countAll(Arg0, Arg1, Arg2, Arg3)); } }G;
int main() { G.run_test(-1); return 0; }
|