• The 2023 ICPC Asia Regionals Online Contest (1) E. Magical Pair(数论 欧拉函数)


    题目

    T(T<=10)组样例,每次给出一个n(2<=n<=1e18),

    询问多少对(x,y)(0<=x,y<=n^2-n),满足x^y\equiv y^x(mod \ n)

    答案对998244353取模,保证n-1不是998244353倍数

    思路来源

    OEIS、SSerxhs、官方题解

    2023 ICPC 网络赛 第一场简要题解 - 知乎

    题解

    官方题解还没有补,OEIS打了个表然后就通过了

    这里给一下SSerxhs教的做法吧(图源:我、tanao学弟)

    SSerxhs代码

    我的理解

    首先,证一下这个和\sum_{i=0}^{p-2}b_{i}^2是等价的,其中bi为满足x^y\equiv i的(x,y)的对数

    关于这部分,题解里给的中国剩余定理的构造,也很巧妙

    剩下的部分就很神奇了,首先需要注意到各个素因子的贡献是独立的,可以连积

    对于求某个素因子的幂次的贡献时,用到了解的分布是均匀的性质

    代码1(OEIS)

    1. #include
    2. using namespace std;
    3. #define In inline
    4. typedef long long ll;
    5. typedef double db;
    6. const int INF = 0x3f3f3f3f;
    7. const db eps = 1e-8;
    8. mapans;
    9. inline ll read()
    10. {
    11. ll ans = 0;
    12. char ch = getchar(), last = ' ';
    13. while(!isdigit(ch)) {last = ch; ch = getchar();}
    14. while(isdigit(ch)) {ans = (ans << 1) + (ans << 3) + ch - '0'; ch = getchar();}
    15. if(last == '-') ans = -ans;
    16. return ans;
    17. }
    18. inline void write(ll x)
    19. {
    20. if(x < 0) x = -x, putchar('-');
    21. if(x >= 10) write(x / 10);
    22. putchar(x % 10 + '0');
    23. }
    24. ll n;
    25. In ll mul(ll a, ll b, ll mod)
    26. {
    27. ll d = (long double)a / mod * b + 1e-8;
    28. ll r = a * b - d * mod;
    29. return r < 0 ? r + mod : r;
    30. }
    31. In ll quickpow(ll a, ll b, ll mod)
    32. {
    33. ll ret = 1;
    34. for(; b; b >>= 1, a = mul(a, a, mod))
    35. if(b & 1) ret = mul(ret, a, mod);
    36. return ret;
    37. }
    38. In bool test(ll a, ll d, ll n)
    39. {
    40. ll t = quickpow(a, d, n);
    41. if(t == 1) return 1;
    42. while(d != n - 1 && t != n - 1 && t != 1) t = mul(t, t, n), d <<= 1;
    43. return t == n - 1;
    44. }
    45. int a[] = {2, 3, 5, 7, 11};
    46. In bool miller_rabin(ll n)
    47. {
    48. if(n == 1) return 0;
    49. for(int i = 0; i < 5; ++i)
    50. {
    51. if(n == a[i]) return 1;
    52. if(!(n % a[i])) return 0;
    53. }
    54. ll d = n - 1;
    55. while(!(d & 1)) d >>= 1;
    56. for(int i = 1; i <= 5; ++i)
    57. {
    58. ll a = rand() % (n - 2) + 2;
    59. if(!test(a, d, n)) return 0;
    60. }
    61. return 1;
    62. }
    63. In ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    64. In ll f(ll x, ll a, ll mod) {return (mul(x, x, mod) + a) % mod;}
    65. const int M = (1 << 7) - 1;
    66. ll pollard_rho(ll n)
    67. {
    68. for(int i = 0; i < 5; ++i) if(n % a[i] == 0) return a[i];
    69. ll x = rand(), y = x, t = 1, a = rand() % (n - 2) + 2;
    70. for(int k = 2;; k <<= 1, y = x)
    71. {
    72. ll q = 1;
    73. for(int i = 1; i <= k; ++i)
    74. {
    75. x = f(x, a, n);
    76. q = mul(q, abs(x - y), n);
    77. if(!(i & M))
    78. {
    79. t = gcd(q, n);
    80. if(t > 1) break;
    81. }
    82. }
    83. if(t > 1 || (t = gcd(q, n)) > 1) break;
    84. }
    85. return t;
    86. }
    87. In void find(ll x)
    88. {
    89. if(x == 1 ) return;
    90. if(miller_rabin(x)) {ans[x]++;return;}
    91. ll p = x;
    92. while(p == x) p = pollard_rho(x);
    93. while(x % p == 0) x/=p;
    94. find(p); find(x);
    95. }
    96. const ll mod=998244353;
    97. ll modpow(ll x,ll n){
    98. x%=mod;
    99. if(!x)return 0;
    100. ll res=1;
    101. for(;n;n>>=1,x=1ll*x*x%mod){
    102. if(n&1)res=1ll*res*x%mod;
    103. }
    104. return res;
    105. }
    106. ll cal(ll p,ll e){
    107. //printf("p:%lld e:%lld\n",p,e);
    108. return (modpow(p,e+1)+modpow(p,e)-1+mod)%mod*modpow(p,2*e-1)%mod;
    109. }
    110. int main()
    111. {
    112. srand(time(0));
    113. int T = read();
    114. while(T--)
    115. {
    116. ans.clear();
    117. n = read();
    118. ll m=n-1;
    119. find(m);
    120. ll phi=m%mod,res=1;
    121. for(auto &v:ans){
    122. ll p=v.first,e=0;
    123. while(m%p==0)m/=p,e++;
    124. res=res*cal(p,e)%mod;
    125. }
    126. res=(res+phi*phi%mod)%mod;
    127. printf("%lld\n",res);
    128. }
    129. return 0;
    130. }

    代码2(SSerxhs代码)

    1. #include
    2. using namespace std;
    3. #define In inline
    4. typedef long long ll;
    5. typedef double db;
    6. typedef pairint> P;
    7. #define rep(i,a,b) for(int i=(a);i<=(b);++i)
    8. const int INF = 0x3f3f3f3f;
    9. const db eps = 1e-8;
    10. mapint>ans;
    11. vector

      ans2;

    12. inline ll read()
    13. {
    14. ll ans = 0;
    15. char ch = getchar(), last = ' ';
    16. while(!isdigit(ch)) {last = ch; ch = getchar();}
    17. while(isdigit(ch)) {ans = (ans << 1) + (ans << 3) + ch - '0'; ch = getchar();}
    18. if(last == '-') ans = -ans;
    19. return ans;
    20. }
    21. inline void write(ll x)
    22. {
    23. if(x < 0) x = -x, putchar('-');
    24. if(x >= 10) write(x / 10);
    25. putchar(x % 10 + '0');
    26. }
    27. ll n;
    28. In ll mul(ll a, ll b, ll mod)
    29. {
    30. ll d = (long double)a / mod * b + 1e-8;
    31. ll r = a * b - d * mod;
    32. return r < 0 ? r + mod : r;
    33. }
    34. In ll quickpow(ll a, ll b, ll mod)
    35. {
    36. ll ret = 1;
    37. for(; b; b >>= 1, a = mul(a, a, mod))
    38. if(b & 1) ret = mul(ret, a, mod);
    39. return ret;
    40. }
    41. In bool test(ll a, ll d, ll n)
    42. {
    43. ll t = quickpow(a, d, n);
    44. if(t == 1) return 1;
    45. while(d != n - 1 && t != n - 1 && t != 1) t = mul(t, t, n), d <<= 1;
    46. return t == n - 1;
    47. }
    48. int a[] = {2, 3, 5, 7, 11};
    49. In bool miller_rabin(ll n)
    50. {
    51. if(n == 1) return 0;
    52. for(int i = 0; i < 5; ++i)
    53. {
    54. if(n == a[i]) return 1;
    55. if(!(n % a[i])) return 0;
    56. }
    57. ll d = n - 1;
    58. while(!(d & 1)) d >>= 1;
    59. for(int i = 1; i <= 5; ++i)
    60. {
    61. ll a = rand() % (n - 2) + 2;
    62. if(!test(a, d, n)) return 0;
    63. }
    64. return 1;
    65. }
    66. In ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    67. In ll f(ll x, ll a, ll mod) {return (mul(x, x, mod) + a) % mod;}
    68. const int M = (1 << 7) - 1;
    69. ll pollard_rho(ll n)
    70. {
    71. for(int i = 0; i < 5; ++i) if(n % a[i] == 0) return a[i];
    72. ll x = rand(), y = x, t = 1, a = rand() % (n - 2) + 2;
    73. for(int k = 2;; k <<= 1, y = x)
    74. {
    75. ll q = 1;
    76. for(int i = 1; i <= k; ++i)
    77. {
    78. x = f(x, a, n);
    79. q = mul(q, abs(x - y), n);
    80. if(!(i & M))
    81. {
    82. t = gcd(q, n);
    83. if(t > 1) break;
    84. }
    85. }
    86. if(t > 1 || (t = gcd(q, n)) > 1) break;
    87. }
    88. return t;
    89. }
    90. In void find(ll x)
    91. {
    92. if(x == 1 ) return;
    93. if(miller_rabin(x)) {ans[x]++;return;}
    94. ll p = x;
    95. while(p == x) p = pollard_rho(x);
    96. while(x % p == 0) x/=p;
    97. find(p); find(x);
    98. }
    99. const ll mod=998244353;
    100. ll modpow(ll x,ll n){
    101. x%=mod;
    102. if(!x)return 0;
    103. ll res=1;
    104. for(;n;n>>=1,x=1ll*x*x%mod){
    105. if(n&1)res=1ll*res*x%mod;
    106. }
    107. return res;
    108. }
    109. ll cal(ll p,ll e){
    110. //printf("p:%lld e:%lld\n",p,e);
    111. return (modpow(p,e+1)+modpow(p,e)-1+mod)%mod*modpow(p,2*e-1)%mod;
    112. }
    113. ll sol(){
    114. ll ta=1;//tt=1;
    115. for(auto &x:ans2){
    116. ll p=x.first,ans=0;
    117. int k=x.second;
    118. p%=mod;
    119. vector f(k+1),pw(k+1),num(k+1);
    120. pw[0]=1;
    121. rep(i,1,k)pw[i]=pw[i-1]*p%mod;
    122. rep(i,0,k-1)num[i]=(pw[k-i]+mod-pw[k-i-1])%mod;
    123. num[k]=1;
    124. rep(i,0,k){
    125. ll ni=num[i];
    126. rep(j,0,k){
    127. ll nj=num[j];
    128. f[min(k,i+j)]=(f[min(k,i+j)]+ni*nj%mod)%mod;
    129. }
    130. }
    131. rep(i,0,k){
    132. ll tmp=f[i]*modpow(num[i],mod-2)%mod;
    133. ans=(ans+tmp*tmp%mod*num[i]%mod)%mod;
    134. }
    135. ta=ta*ans%mod;
    136. }
    137. return ta;
    138. }
    139. int main()
    140. {
    141. srand(time(0));
    142. int T = read();
    143. while(T--)
    144. {
    145. ans.clear();
    146. ans2.clear();
    147. n = read();
    148. ll m=n-1;
    149. find(m);
    150. //ll phi=m%mod,res=1;
    151. for(auto &v:ans){
    152. ll p=v.first,e=0;
    153. while(m%p==0)m/=p,e++;
    154. ans2.push_back(P(p,e));
    155. //res=res*cal(p,e)%mod;
    156. }
    157. m=(n-1)%mod;
    158. ll res=sol();
    159. res=(res+m*m%mod)%mod;
    160. printf("%lld\n",res);
    161. //res=(res+phi*phi%mod)%mod;
    162. //printf("%lld\n",res);
    163. }
    164. return 0;
    165. }

  • 相关阅读:
    LVGL---基础对象的事件(events)
    Netty原理与基础
    python 装饰器
    【树莓派不吃灰】使用frp内网穿透,实现远程访问树莓派
    Nginx篇---第三篇
    【Qt】界面优化
    使用Postman拦截浏览器请求
    java常见题
    MasterAlign相机参数设置-曝光时间调节
    我这个代码可以通过深度优先搜索实现逆拓扑排序时检测出有回路的存在吗
  • 原文地址:https://blog.csdn.net/Code92007/article/details/133254179