[杂题训练]CF1228E Another Filling the Grid(容斥),CF936C Lock Puzzle(构造)
文章目錄
- T1:CF1228E Another Filling the Grid
- solution
- code
- T2:CF936C Lock Puzzle
- solution
- code
T1:CF1228E Another Filling the Grid
點我
solution
反過來思考,用所有方案數?不合法方案數
很容易想到的是——容斥!!
首先只考慮行數
減去至少一行沒有111的方案數,加上至少兩行沒有111的方案數…
得出以下柿子
∑i=0n(?1)i×Cni×(k?1)i×n×kn2?i×n\sum_{i=0}^n(-1)^i\times C_n^i\times (k-1)^{i\times n}\times k^{n^2-i\times n}i=0∑n?(?1)i×Cni?×(k?1)i×n×kn2?i×n
(枚舉iii行不含111,那么這iii行共i×ni\times ni×n個格子,除了111不能填,只有k?1k-1k?1個數可以填,剩下的n2?i×nn^2-i\times nn2?i×n格子kkk個數都可以填)
再加上列的限制
∑i=0n∑j=0n(?1)i+j×Cni×Cnj×(k?1)i×n+j×n?i×j×kn2?(i×n+j×n?i×j)\sum_{i=0}^n\sum_{j=0}^n(-1)^{i+j}\times C_n^i\times C_n^j\times (k-1)^{i\times n+j\times n-i\times j}\times k^{n^2-(i\times n+j\times n-i\times j)}i=0∑n?j=0∑n?(?1)i+j×Cni?×Cnj?×(k?1)i×n+j×n?i×j×kn2?(i×n+j×n?i×j)
(iii行與jjj列包含的格子數=i\ =\ i?=?i行包含的格子數i×n+ji\times n\ +\ ji×n?+?j列包含的格子數?i,j\ -\ i,j???i,j共同包含的格子數i×ji\times ji×j)
到這里,O(n2)O(n^2)O(n2)已經可以悠閑地過這道題了,但是我們要 沒事找事吃飽了撐的 熱愛學習,深度挖掘,萬一nnn一下子猛加到1e5,1e61e5,1e61e5,1e6級別呢??
換言之,我們是否還能再找到一個O(nlogn)O(nlogn)O(nlogn)的優秀算法呢??
答案當然是ofcourse,whynotof\ course,why\ notof?course,why?not
來化一下上面的優美柿子
(k?1)i×n+j×n?i×j×kn2?(i×n+j×n?i×j)(k-1)^{i\times n+j\times n-i\times j}\times k^{n^2-(i\times n+j\times n-i\times j)}(k?1)i×n+j×n?i×j×kn2?(i×n+j×n?i×j)
=(k?1)i×(n?j)×(k?1)j×n×k(n?i)(n?j)=(k-1)^{i\times (n-j)}\times (k-1)^{j\times n}\times k^{(n-i)(n-j)}=(k?1)i×(n?j)×(k?1)j×n×k(n?i)(n?j)
=[(k?1)i](n?j)×[(k?1)n]j×(kn?i)n?j=[(k-1)^i]^{(n-j)}\times [(k-1)^n]^j\times (k^{n-i})^{n-j}=[(k?1)i](n?j)×[(k?1)n]j×(kn?i)n?j
=[(k?1)i×kn?i]n?j×[(k?1)n]j=[(k-1)^i\times k^{n-i}]^{n-j}\times [(k-1)^n]^j=[(k?1)i×kn?i]n?j×[(k?1)n]j
到這里就非常明顯了,讓我們換個硬元更加明顯
令x=(k?1)i×kn?i,y=(k?1)nx=(k-1)^i\times k^{n-i},y=(k-1)^nx=(k?1)i×kn?i,y=(k?1)n
則上述柿子可變為xn?j×yjx^{n-j}\times y^jxn?j×yj
太像我們的二項式小可愛了,但是不要 不穿褲子就不跑 ,還少了點什么,我們需要把前面的
(?1)j×Cnj(-1)^j\times C_n^j(?1)j×Cnj?提過來才行
(?1)j×Cnj×xn?j×yj=(x?y)n(-1)^j\times C_n^j\times x^{n-j}\times y^j=(x-y)^n(?1)j×Cnj?×xn?j×yj=(x?y)n
于是答案柿子就可以剔除jjj,只剩下與iii有關的柿子了
∑i=0n(?1)i×Cni×[(k?1)i×kn?i+(k?1)n]n\sum_{i=0}^n(-1)^i\times C_n^i\times [(k-1)^i\times k^{n-i}+(k-1)^n]^ni=0∑n?(?1)i×Cni?×[(k?1)i×kn?i+(k?1)n]n
次方就找快速冪qkpowqkpowqkpow老火雞完成,時間復雜度就成功降為O(nlong)O(nlong)O(nlong)
當然kkk的冪次可以提前預處理,這樣可以少跑幾次快速冪,優化可能有 個芝麻大點
code
#include <cstdio> #define int long long #define mod 1000000007 #define maxn 300 int n, k; int fac[maxn], inv[maxn];int qkpow( int x, int y ) {int ans = 1;while( y ) {if( y & 1 ) ans = ans * x % mod;x = x * x % mod;y >>= 1;}return ans; }int C( int n, int m ) {if( n < m ) return 0;return fac[n] * inv[m] % mod * inv[n - m] % mod; }signed main() {scanf( "%lld %lld", &n, &k );fac[0] = inv[0] = 1;for( int i = 1;i <= n;i ++ )fac[i] = fac[i - 1] * i % mod;inv[n] = qkpow( fac[n], mod - 2 );for( int i = n - 1;i;i -- ) inv[i] = inv[i + 1] * ( i + 1 ) % mod;int ans = 0;for( int i = 0;i <= n;i ++ ) {if( i & 1 )ans = ( ans - C( n, i ) * qkpow( ( qkpow( k - 1, i ) * qkpow( k, n - i ) % mod - qkpow( k - 1, n ) + mod ) % mod, n ) % mod + mod ) % mod;elseans = ( ans + C( n, i ) * qkpow( ( qkpow( k - 1, i ) * qkpow( k, n - i ) % mod - qkpow( k - 1, n ) + mod ) % mod, n ) % mod ) % mod;} printf( "%lld", ans );return 0; }T2:CF936C Lock Puzzle
戳一戳
solution
一般這種限制多少次以內就算成功的題目肯定是個構造題!!
觀察數據范圍n≤2000n\le 2000n≤2000,操作次數≤6100\le 6100≤6100
大膽猜想應該讓我們用3×n3\times n3×n的操作左右完成構造
即對于每一個字符最多只用333步就讓ta鎖定在我們想要ta在的位置
直接說正解吧
假設現在的sss串長下列樣子
AxBCA\ x\ B\ CA?x?B?C
A,B,CA,B,CA,B,C均為一個字符子串,CCC稍特殊一點,既是sss串的后綴,同時要為ttt串的前綴,且最長
當然三個串可以為空
xxx為我們想移動的字符
現在目標是將xxx移動到CCC后面一個,即CxCxCx構成一個新的ttt的前綴
操作①:shiftlen(BC)shift\ len(BC)shift?len(BC)
原串變為 C′B′AxC'\ B'\ A\ xC′?B′?A?x
操作②:shiftlen(1)shift\ len(1)shift?len(1)
繼續變為 xC′B′Ax\ C'\ B'\ Ax?C′?B′?A
操作③:shiftlen(n?1)shift\ len(n-1)shift?len(n?1)
成為 A′BCxA'\ B\ C\ xA′?B?C?x
我們只關心CxCxCx是否一起出現在最后面,前面的AAA是否顛倒,不在乎滴
code
#include <cstdio> #include <iostream> #include <algorithm> using namespace std; #define maxn 2005 int n, tot; char s[maxn], t[maxn]; int tot_s[maxn], tot_t[maxn], ans[maxn << 2];int main() {scanf( "%d %s %s", &n, s + 1, t + 1 );for( int i = 1;i <= n;i ++ )tot_s[s[i]] ++, tot_t[t[i]] ++;for( int i = 'a';i <= 'z';i ++ )if( tot_s[i] != tot_t[i] ) return ! printf( "-1\n" );int cnt = 0;for( int i = 1;i <= n;i ++ )if( s[i] == t[1] ) {bool flag = 1;for( int j = i;j <= n;j ++ )if( s[j] != t[j - i + 1] ) {flag = 0;break;}if( flag ) {cnt = n - i + 1;break;}}while( 1 ) {bool flag = 1;for( int i = 1;i <= n;i ++ )if( s[i] != t[i] ) {flag = 0;break;}if( flag ) break;int pos;for( int i = 1;i <= n - cnt;i ++ )if( s[i] == t[cnt + 1] ) {pos = i;break;}ans[++ tot] = n - pos;ans[++ tot] = 1;ans[++ tot] = n - 1;if( pos > 1 ) reverse( s + 1, s + pos );char temp = s[pos];for( int i = pos;i < n;i ++ )s[i] = s[i + 1]; s[n] = temp;cnt ++;}printf( "%d\n", tot );for( int i = 1;i <= tot;i ++ )printf( "%d ", ans[i] );return 0; }總結
以上是生活随笔為你收集整理的[杂题训练]CF1228E Another Filling the Grid(容斥),CF936C Lock Puzzle(构造)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第五人格怎么获得回声/回声有什么作用
- 下一篇: 微信又更新了微信又更新了规则