NowCoder2018多校A Ternary String 拓展尤拉定理
阿新 • • 發佈:2021-10-05
NowCoder2018多校A Ternary String 拓展尤拉定理
題意
給定帶前導0的三進位制數,每秒自動進行一次操作,1的後面多一個0,2的後面多一個1,開頭的字元被刪除,求這個數變為空的操作次數
求操作次數取模\(1e9+7\)
\[1 \leq |s| \leq 10^5 \]分析
考慮記錄時間,原串中每個數帶來的貢獻,可以簡單歸納得出
0:\(t + 1\)
1:\(2(t + 1)\)
2:\(3(2^{t + 1} - 1)\)
操作12都可以輕鬆得到結果,對於3,計算\(2^{t + 1} \ mod \ MOD\)是不方便的,考慮使用拓展尤拉定理
\[a^b \equiv \begin{cases} a^{b \bmod \varphi(m)},gcd(a,m) = 1\\ a^b ,gcd(a,m) \neq 1,b \leq \varphi(m) (mod \ m)\\ a^{b \ mod \varphi(m) +\varphi(m)},gcd(a,m) \neq 1,b \geq \varphi(m) \end{cases} \]使用時,要求冪對\(\varphi(m)\)
為了方便實現,可以採用DFS的方式記錄當前第幾個數和當前的模數,至於為什麼不用判斷\(b \geq \varphi(m)\),我也不是很懂
程式碼
const int MOD = (int)1e9 + 7; int m[35],ans[35]; inline int mul(int a,int b,int i){ return (ll)a * b % i; } inline void add(int &a,int b,int i){ a += b; if(a >= i) a -= i; } inline int ksm(int a,ll b = MOD - 2,int m = MOD){ int ans = 1; int base = a; while(b){ if(b & 1) { ans = (ll)ans * base % m; } base = (ll)base * base % m; b >>= 1; } return ans; } inline int get_phi(int n) { int m = int(sqrt(n + 0.5)); int ans = n; for (int i = 2; i <= m; i++) { if (n % i == 0) { ans = ans / i * (i - 1); while (n % i == 0) n /= i; } } if (n > 1) ans = ans / n * (n - 1); return ans; } unordered_map<int,int> mp; char s[100005]; int dfs(int len,int m){ if(!len) return 0; if(s[len] == '0') return (dfs(len - 1,m) + 1) % m; if(s[len] == '1') return (ll)2 * (dfs(len - 1,m) + 1) % m; //if(mp[m] != 1) return (mul(3,ksm(2,(dfs(len - 1,mp[m]) + 1) % mp[m],m),m) + m - 3) % m; int p = dfs(len - 1,mp[m]) + 1; if(m != 1 && m != MOD) { if(p >= mp[m]) return (mul(3,ksm(2,p % mp[m] + mp[m],m),m) + m - 3) % m; else return (mul(3,ksm(2,p % mp[m],m),m) + m - 3) % m; } return (mul(3,ksm(2,p % mp[m],m),m) + m - 3) % m; } int main(){ int T = rd(); int tmp = MOD; mp[1] = 1; while(tmp > 1) { mp[tmp] = get_phi(tmp); tmp = mp[tmp]; } while(T--){ scanf("%s",s + 1); int len = strlen(s + 1); printf("%d\n",dfs(len,MOD)); } }