题意
给定一个长度为 n n n 的字符串 s s s 代表 A A A 的工作模式:第 i i i 个字符为 #
代表 A A A 在第 i i i 天工作,为 .
代表 A A A 在第 i i i 天不工作。现构造一个长度为 m m m 的字符串 t ′ t' t ′ (m m m 是 n n n 的因子且 m ≠ n m\neq n m = n ) ,将其拷贝 n m \dfrac{n}{m} m n 份得到字符串 t t t ,代表 B B B 的工作模式。 要求在这 n n n 天中,每一天都至少有一人工作。求不同的字符串 t t t 的数量。
题解
记 f ( n ) f(n) f ( n ) 为长度为 n n n 的字符串 t ′ t' t ′ 能生成的不同字符串 t t t 的数量。注意到,长度是 n n n 的因子的字符串 t ′ ′ t'' t ′′ 生成的字符串可能和 t ′ t' t ′ 生成的相同,例如:t ′ t' t ′ 为 ##
而 t ′ ′ t'' t ′′ 为 #
。所以,我们再定义 g ( n ) g(n) g ( n ) 为长度为 n n n 的字符串 t ′ t' t ′ 能生成的,且不能由更短的字符串生成的不同字符串 t t t 的数量。
最终我们要求的式子为
∑ i ∣ n , i ≠ n g ( i ) \sum_{i\mid n,i\neq n}g(i)
i ∣ n , i = n ∑ g ( i )
直接求 g g g 不太好求,但是 f f f 容易求得。所以考虑 f f f 和 g g g 的关系
f ( n ) = ∑ d ∣ n g ( d ) f(n)=\sum_{d|n}g(d)
f ( n ) = d ∣ n ∑ g ( d )
这是莫比乌斯反演的经典形式,很容易得到
g ( n ) = ∑ d ∣ n μ ( d ) f ( n d ) g(n)=\sum_{d|n}\mu(d)f(\frac{n}{d})
g ( n ) = d ∣ n ∑ μ ( d ) f ( d n )
接下来就是推式子
∑ i ∣ n , i ≠ n g ( i ) = ∑ i ∣ n , i ≠ n ∑ d ∣ n μ ( d ) f ( n d ) = ∑ d ∣ n , d ≠ n f ( d ) ∑ k ∣ n , k ≠ n d μ ( d ) = ∑ d ∣ n , d ≠ n f ( d ) ( ϵ ( n d ) − μ ( n d ) ) = ∑ d ∣ n , d ≠ n − μ ( n d ) f ( d ) \begin{aligned}
\sum_{i\mid n,i\neq n}g(i)
&=\sum_{i\mid n,i\neq n}\sum_{d\mid n}\mu(d)f(\frac{n}{d})\\
&=\sum_{d\mid n,d\neq n}f(d)\sum_{k\mid n,k\neq \frac{n}{d}}\mu(d)\\
&=\sum_{d\mid n,d\neq n}f(d)(\epsilon(\frac{n}{d})-\mu(\frac{n}{d}))\\
&=\sum_{d\mid n,d\neq n}-\mu(\frac{n}{d})f(d)
\end{aligned}
i ∣ n , i = n ∑ g ( i ) = i ∣ n , i = n ∑ d ∣ n ∑ μ ( d ) f ( d n ) = d ∣ n , d = n ∑ f ( d ) k ∣ n , k = d n ∑ μ ( d ) = d ∣ n , d = n ∑ f ( d ) ( ϵ ( d n ) − μ ( d n )) = d ∣ n , d = n ∑ − μ ( d n ) f ( d )
然后这个题目就做完了qwq。
代码
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 #include <bits/stdc++.h> using namespace std;typedef long long ll;const int maxn=1e5 ;const int p=998244353 ;int n,cnt,f[maxn+5 ],vis[maxn+5 ],pri[maxn+5 ],mu[maxn+5 ],tag[maxn+5 ]; ll P2[maxn+5 ]; string s;void init () { mu[1 ]=1 ; for (int i=2 ;i<=maxn;i++) { if (!vis[i]) pri[++cnt]=i,mu[i]=-1 ; for (int j=1 ;j<=cnt&&i*pri[j]<=maxn;j++) { vis[i*pri[j]]=1 ; if (i%pri[j]==0 ) { mu[i*pri[j]]=0 ; break ; } mu[i*pri[j]]=-mu[i]; } } P2[0 ]=1 ; for (int i=1 ;i<=maxn;i++) P2[i]=P2[i-1 ]*2 %p; }void solve (int m) { for (int i=1 ;i<=m;i++) tag[i]=0 ; for (int i=0 ;i<n;i++) if (s[i]=='.' ) tag[i%m+1 ]=1 ; int cnt=0 ; for (int i=1 ;i<=m;i++) if (!tag[i]) cnt++; f[m]=P2[cnt]; }int main () { ios::sync_with_stdio (false ); cin.tie (nullptr ); init (); cin>>n>>s; ll ans=0 ; for (int i=1 ;i<n;i++) { if (n%i) continue ; solve (i); ans=(ans-mu[n/i]*f[i]%p+p)%p; } cout<<ans<<'\n' ; return 0 ; }
题意
给定一张有向图,含有一些边 ( s i , t i ) (s_i,t_i) ( s i , t i ) 。同时,给出一些限制 ( l i , r i ) (l_i,r_i) ( l i , r i ) 。要求构造一个排列 p p p ,满足以下条件:
p s i < p t i p_{s_i}<p_{t_i} p s i < p t i
l i ≤ p i ≤ r i l_i\leq p_i\leq r_i l i ≤ p i ≤ r i
题解
很显然这张图一定是DAG,否则无法满足条件1。
由于存在拓扑关系,每个限制 ( l i , r i ) (l_i,r_i) ( l i , r i ) 事实上也会限制每个点的前驱。具体地,对于边 ( s , t ) (s,t) ( s , t ) ,有 p s ≤ r s p_s\leq r_s p s ≤ r s 且 p s ≤ p t − 1 ≤ r t p_s\leq p_t-1\leq r_t p s ≤ p t − 1 ≤ r t 。即 p s ≤ min ( r s , r t − 1 ) p_s\leq \min(r_s,r_t-1) p s ≤ min ( r s , r t − 1 ) 。所以,在反图上跑一遍拓扑序,更新一下每个点的上界,保证对每条边 ( s , t ) (s,t) ( s , t ) ,有 r s < r t r_s<r_t r s < r t 。
接下来考虑构造这个排列,从 1 1 1 到 n n n 依次将每个数分配,在分配 i i i 时,候选点 v v v 需要满足两个条件:
l v ≤ i l_v\leq i l v ≤ i
v v v 的所有前驱都已被分配了数
在所有候选点中,选择 r r r 最小的,将 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 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 #include <bits/stdc++.h> using namespace std;const int maxn=2e5 +5 ;int p[maxn],in[maxn],in1[maxn]; vector<int > a[maxn]; vector<int > g[maxn],g1[maxn];struct node { int id,l,r; bool operator < (const node x) const {return r>x.r;} }nodes[maxn];int main () { ios::sync_with_stdio (false ); cin.tie (nullptr ); int n,m;cin>>n>>m; for (int i=1 ;i<=m;i++) { int u,v;cin>>u>>v; g[u].push_back (v),g1[v].push_back (u); in[v]++,in1[u]++; } for (int i=1 ;i<=n;i++) { int l,r;cin>>l>>r; nodes[i]={i,l,r}; a[l].push_back (i); } queue<int > q; for (int i=1 ;i<=n;i++) if (!in1[i]) q.push (i); int cnt=0 ; while (!q.empty ()) { int u=q.front ();q.pop (); cnt++; for (auto v:g1[u]) { nodes[v].r=min (nodes[v].r,nodes[u].r-1 ); in1[v]--; if (!in1[v]) q.push (v); } } if (cnt!=n) cout<<"No" <<'\n' ; else { priority_queue<node> pq; for (int i=1 ;i<=n;i++) { for (auto j:a[i]) if (!in[j]) pq.push (nodes[j]); if (pq.empty ()) break ; int u=pq.top ().id;pq.pop (); p[u]=i; for (auto v:g[u]) { in[v]--; if (!in[v]&&nodes[v].l<=i) pq.push (nodes[v]); } } bool ok=1 ; for (int i=1 ;i<=n;i++) { if (p[i]<nodes[i].l||p[i]>nodes[i].r) ok=0 ; for (auto j:g[i]) if (p[j]<p[i]) ok=0 ; } if (!ok) cout<<"No" <<'\n' ; else { cout<<"Yes" <<'\n' ; for (int i=1 ;i<=n;i++) cout<<p[i]<<" \n" [i==n]; } } return 0 ; }