https://atcoder.jp/contests/abc212
F - Greedy Takahashi
题意
有 n n n 座城市,m m m 辆公交车。第 i i i 辆公交车从 a i a_i a i 开往 b i b_i b i ,出发时间为 s i + 0.5 s_i+0.5 s i + 0.5 ,到达时间为 t i + 0.5 t_i+0.5 t i + 0.5 。当高桥到达某座城市时,他会等待直到第一辆公交车到达,并坐上这辆公交,如果没有公交车到达,则留在这座城市(保证公交车的到达时间各不相同)。有 q q q 组询问,每组 ( x , y , z ) (x,y,z) ( x , y , z ) 表示高桥如果在 y y y 时间到达 x x x 城市,在 z z z 时间会在哪里。如果在公交车上,输出公交车的起点和终点,否则输出所在城市。
数据范围:n , m , q ≤ 1 0 5 n,m,q\leq 10^5 n , m , q ≤ 1 0 5 。
题解
对于每个城市,高桥的最终位置与到达城市的时间有关。但我们考虑每辆公交车,高桥的最终位置就被确定了。可以利用倍增维护:记 f i , j f_{i,j} f i , j 表示第 i i i 辆公交车后乘坐的第 2 j 2^j 2 j 辆公交车的编号,f i , 0 f_{i,0} f i , 0 即到达第 i i i 辆公交车的终点后乘坐的第一辆公交车的编号。
代码
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 #include <bits/stdc++.h> using namespace std;typedef pair<int ,int > pii;const int N=1e5 +5 ; vector<pii> g[N];struct edge { int a,b,s,t; }e[N];int f[N][25 ];int get (int u,int val) { auto it=lower_bound (g[u].begin (),g[u].end (),make_pair (val,0 )); if (it==g[u].end ()) return -1 ; else return it->second; }int main () { ios::sync_with_stdio (false ); cin.tie (nullptr ); int n,m,q;cin>>n>>m>>q; for (int i=1 ;i<=m;i++) { int a,b,s,t;cin>>a>>b>>s>>t; e[i]={a,b,s,t}; g[a].push_back ({s,i}); } for (int i=1 ;i<=n;i++) sort (g[i].begin (),g[i].end ()); memset (f,-1 ,sizeof (f)); for (int i=1 ;i<=m;i++) f[i][0 ]=get (e[i].b,e[i].t); for (int j=0 ;j<20 ;j++) for (int i=1 ;i<=m;i++) if (f[i][j]!=-1 ) f[i][j+1 ]=f[f[i][j]][j]; while (q--) { int x,y,z;cin>>x>>y>>z; int u=get (y,x); if (u==-1 ||z<=e[u].s) { cout<<y<<'\n' ; continue ; } for (int j=20 ;j>=0 ;j--) if (f[u][j]!=-1 &&e[f[u][j]].s<z) u=f[u][j]; if (z>e[u].t) cout<<e[u].b<<'\n' ; else cout<<e[u].a<<' ' <<e[u].b<<'\n' ; } return 0 ; }
G - Power Pair
题意
求满足
0 ≤ x , y ≤ p − 1 0\leq x,y\leq p-1 0 ≤ x , y ≤ p − 1
存在正整数 n n n ,使得 x n ≡ y ( m o d p ) x^n\equiv y\pmod p x n ≡ y ( mod p )
的 ( x , y ) (x,y) ( x , y ) 的对数,结果对 998244353 998244353 998244353 取模。
数据范围:2 ≤ p ≤ 1 0 12 2\leq p\leq 10^{12} 2 ≤ p ≤ 1 0 12 ,p p p 是质数。
题解
根据阶的定义,要求的就是
1 + ∑ i = 1 p − 1 δ p ( i ) 1+\sum_{i=1}^{p-1}\delta_p(i)
1 + i = 1 ∑ p − 1 δ p ( i )
对于质数 p p p 有 δ p ( x ) = φ ( p ) gcd ( φ ( p ) , x ) \delta_p(x)=\dfrac{\varphi(p)}{\gcd(\varphi(p),x)} δ p ( x ) = g cd( φ ( p ) , x ) φ ( p ) , 则原式可化为
1 + ∑ i = 1 p − 1 φ ( p ) gcd ( φ ( p ) , i ) 1+\sum_{i=1}^{p-1}\dfrac{\varphi(p)}{\gcd(\varphi(p),i)}
1 + i = 1 ∑ p − 1 g cd( φ ( p ) , i ) φ ( p )
令 n = p − 1 n=p-1 n = p − 1 ,则
= 1 + ∑ i = 1 n n gcd ( n , i ) = 1 + ∑ d ∣ n ∑ i = 1 n d n d [ gcd ( n , i × d ) = d ] = 1 + ∑ d ∣ n ∑ i = 1 n d n d [ gcd ( n d , i ) = 1 ] = 1 + ∑ d ∣ n n d φ ( n d ) = 1 + ∑ d ∣ n d φ ( d ) \begin{aligned}
&=1+\sum_{i=1}^n\dfrac{n}{\gcd(n,i)}\\
&=1+\sum_{d|n}\sum_{i=1}^{\frac{n}{d}}\frac{n}{d}[\gcd(n,i\times d)=d]\\
&=1+\sum_{d|n}\sum_{i=1}^{\frac{n}{d}}\frac{n}{d}[\gcd(\frac{n}{d},i)=1]\\
&=1+\sum_{d|n}\frac{n}{d}\varphi(\frac{n}{d})\\
&=1+\sum_{d|n}d\varphi(d)
\end{aligned}
= 1 + i = 1 ∑ n g cd( n , i ) n = 1 + d ∣ n ∑ i = 1 ∑ d n d n [ g cd( n , i × d ) = d ] = 1 + d ∣ n ∑ i = 1 ∑ d n d n [ g cd( d n , i ) = 1 ] = 1 + d ∣ n ∑ d n φ ( d n ) = 1 + d ∣ n ∑ d φ ( d )
然后枚举对 n n n 作质因数分解,根据定义求 φ ( d ) \varphi(d) φ ( d ) 就做完了。
另一种理解方式是借助原根:设 p p p 的原根为 g g g ,令 x = g a , y = g b x=g^a,y=g^b x = g a , y = g b ,则 x n ≡ y ( m o d p ) x^n\equiv y\pmod p x n ≡ y ( mod p ) 可写作 g n a ≡ g b ( m o d p ) g^{na}\equiv g^b\pmod p g na ≡ g b ( mod p ) ,即 n a ≡ b ( m o d p − 1 ) na\equiv b\pmod {p-1} na ≡ b ( mod p − 1 ) 。这个问题就相当于,在一个长度为 p − 1 p-1 p − 1 的环上每次走 a a a 步,一共会到达多少个不同的点。这是一个经典问题,答案是 p − 1 gcd ( p − 1 , a ) \dfrac{p-1}{\gcd(p-1,a)} g cd( p − 1 , a ) p − 1 。剩下的推导同上。
代码
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 #include <bits/stdc++.h> using namespace std;typedef long long ll;const int p=998244353 ;ll phi (ll x) { ll ans=x; for (ll i=2 ;i*i<=x;i++) if (x%i==0 ) { ans=ans/i*(i-1 ); while (x%i==0 ) x/=i; } if (x>1 ) ans=ans/x*(x-1 ); return ans; }int main () { ios::sync_with_stdio (false ); cin.tie (nullptr ); ll n;cin>>n; n--; ll ans=1 ; for (ll i=1 ;i*i<=n;i++) if (n%i==0 ) { ans=(ans+(__int128)i*phi (i))%p; if (i*i!=n) ans=(ans+(__int128)n/i*phi (n/i))%p; } cout<<ans<<'\n' ; return 0 ; }
H - Nim Counting
题意
给定 n , k n,k n , k ,给出 k k k 个数 a 1 , a 2 , ⋯ , a k a_1,a_2,\cdots,a_k a 1 , a 2 , ⋯ , a k 。每次可以选定一个数 m m m 满足 1 ≤ m ≤ n 1\leq m\leq n 1 ≤ m ≤ n ,并选定 m m m 堆石子,每堆石子的数量在 a a a 中。求所有先手必胜的方案数,结果对 998244353 998244353 998244353 取模。
数据范围:1 ≤ n ≤ 2 × 1 0 5 , 1 ≤ k < 2 16 , 1 ≤ a i < 2 16 1\leq n\leq 2\times10^5,1\leq k<2^{16},1\leq a_i< 2^{16} 1 ≤ n ≤ 2 × 1 0 5 , 1 ≤ k < 2 16 , 1 ≤ a i < 2 16 。
题解
令 F = ∑ i = 1 k x a i F=\sum\limits_{i=1}^kx^{a_i} F = i = 1 ∑ k x a i ,则答案为 ∑ w > 0 [ x w ] ∑ i = 1 n F i \sum\limits_{w>0}[x^w]\sum\limits_{i=1}^nF^i w > 0 ∑ [ x w ] i = 1 ∑ n F i ,其中 x a o p x b = x a ⊕ b x^a\ op\ x^b=x^{a\oplus b} x a o p x b = x a ⊕ b 。
考虑 G = F 2 G=F^2 G = F 2 ,则
g k = ∑ i ⊕ j = k f i f j g_k=\sum_{i\oplus j=k}f_if_j
g k = i ⊕ j = k ∑ f i f j
所以这就是异或卷积,为了求出 F i F^i F i 每项的系数,可以先做一遍 FWT,然后快速幂,最后再 IFWT 回去就好了。又由于 F W T ( A + B ) = F W T ( A ) + F W T ( B ) FWT(A+B)=FWT(A)+FWT(B) F W T ( A + B ) = F W T ( A ) + F W T ( B ) ,最终每项的系数就是 F − F n + 1 1 − F \dfrac{F-F^{n+1}}{1-F} 1 − F F − F n + 1 。
代码
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 #include <algorithm> #include <bits/stdc++.h> using namespace std;const int N=2e5 +5 ;typedef long long ll;const int mod=998244353 ;const int inv2=499122177 ;const ll Cor[2 ][2 ]={{1 ,0 },{1 ,1 }}, Cand[2 ][2 ]={{1 ,1 },{0 ,1 }}, Cxor[2 ][2 ]={{1 ,1 },{1 ,mod-1 }}, ICor[2 ][2 ]={{1 ,0 },{mod-1 ,1 }}, ICand[2 ][2 ]={{1 ,mod-1 },{0 ,1 }}, ICxor[2 ][2 ]={{inv2,inv2},{inv2,mod-inv2}};ll fpow (ll a,ll b) { ll res=1 ; while (b) { if (b&1 ) res=res*a%mod; a=a*a%mod; b>>=1 ; } return res; }void FWT (ll *F,const ll c[2 ][2 ],int n) { for (int len=1 ;len<n;len<<=1 ) for (int p=0 ;p<n;p+=len+len) for (int i=p;i<p+len;i++) { ll sav0=F[i]; F[i]=(c[0 ][0 ]*F[i]+c[0 ][1 ]*F[i+len])%mod; F[i+len]=(c[1 ][0 ]*sav0+c[1 ][1 ]*F[i+len])%mod; } }void bitmul (ll *F,const ll C[2 ][2 ],const ll IC[2 ][2 ],int n,int k) { FWT (F,C,n); for (int i=0 ;i<n;i++) { if (F[i]==1 ) F[i]=k; else F[i]=(fpow (F[i],k+1 )+mod-F[i])*fpow (F[i]+mod-1 ,mod-2 )%mod; } FWT (F,IC,n); } ll f[N],g[N],a[N],b[N];#define cpy(f,g,n) memcpy(f,g,sizeof(ll)*(n)) int main () { ios::sync_with_stdio (false ); cin.tie (nullptr ); int n,k;cin>>n>>k; for (int i=1 ;i<=k;i++) { int x;cin>>x; f[x]=1 ; } cpy (a,f,(1 <<16 )); bitmul (a,Cxor,ICxor,(1 <<16 ),n); ll ans=0 ; for (int i=1 ;i<(1 <<16 );i++) ans=(ans+a[i])%mod; cout<<ans<<'\n' ; return 0 ; }