日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

test 7 3-22 2021省选模拟赛seven

發布時間:2023/12/3 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 test 7 3-22 2021省选模拟赛seven 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 考試復盤
  • 人生
  • 贏家
  • 黑紅兔

考試復盤

T1T1T1

subtask1:n≤5subtask1:n\le 5subtask1:n5,暴搜點的顏色狀態以及邊的存在狀態

對于一條連接相同顏色點的邊,可要可不要,不會提供形態變化的貢獻,2edge2^{edge}2edge

dpdpdp???

dp[i][j][0/1]dp[i][j][0/1]dp[i][j][0/1]表示前iii個點,顏色為白/黑,由前面jjj個點轉移過來?

好像轉移不動。。pass

T2T2T2

n≤15n\le 15n15??感覺給子任務編號,是不同數據下的算法拼湊而來的呢(〃 ̄︶ ̄)人( ̄︶ ̄〃)

subtask1:m≤20subtask1:m\le 20subtask1:m20,直接2m2^m2m暴搜

竟然空間超限,ε=(・д・`*)ハァ…,哭暈在廁所

subtask2:1?2subtask2:1-2subtask2:1?2之間有唯一的一條簡單路徑

考慮枚舉在這條路徑上的iii點相遇,則除了這條路徑以外的邊的方向都無所謂

subtask3:n≤10→m≤45subtask3:n\le 10\rightarrow m\le 45subtask3:n10m45

subtask4:subtask4:subtask4:一般情況

考慮枚舉在點xxx相遇,暴搜1?x1-x1?x每一條路徑,在此基礎上搜2?x2-x2?x的每一條路徑,沒被打標記的邊可選可不選;

但是這里會出現重復的情況,因為路徑并不是唯一的

emmmmmm(▼?▼メ)難搞哦(?。?)

T3T3T3

字符匹配非常類似最近做的FFTFFTFFT題_(:3J∠)

可仔細想想,又不太對勁,pass

猜個小結論:長度是每段只比上一段加一,感覺就是對的

考慮dp[i][j]dp[i][j]dp[i][j],表示串[l,r][l,r][l,r]作為首串,最多能接的段數

轉移,要枚舉位置??比較串,kmpkmpkmp??hashhashhash??,好像時間復雜度有點大誒

算了吧。。。

考后

唯一想說的,對于這場比賽就只有空間超限了,(*゚Д゚)つミ匚___

人生

n≤2e5n\le 2e5n2e5


endiend_iendi?表示以iii為結尾的路徑條數

如果endjend_jendj?是偶數條,連向iii后,endiend_iendi?也只會加上偶數,奇偶性不變

如果endjend_jendj?是奇數條,連向iii后,endiend_iendi?會加上奇數,奇偶性變化

注意endiend_iendi?要加上111,自己到自己的路徑

由此得知,endiend_iendi?奇偶性只跟前面與iii連邊的點中endjend_jendj?是奇數的點的個數有關,與實際點是哪個無關

f[i][j][k][h]f[i][j][k][h]f[i][j][k][h]:表示前iii個點,有jjj個白點和kkk個黑點的endendend是奇數,且前iii個點endendend之和的奇偶性為hhh000111奇)

對于一個nnn元集合(n>1n>1n>1),選出一個偶數子集大小或者是一個奇數子集大小的方案數均為2n?12^{n-1}2n?1


簡單證明一下( ̄▽ ̄)":

nnn為奇數

假設選了iii個,iii為奇數,那么n?in-in?i個沒有選,n?in-in?i為偶數

說明每選一種奇數子集大小的方案,就會存在一種偶數子集大小的方案

各自占一半,=2n2=2n?1=\frac{2^n}{2}=2^{n-1}=22n?=2n?1

nnn為偶數

T(n,1)T(n,1)T(n,1)表示在nnn個中選奇數個的方案數,T(n,0)T(n,0)T(n,0)表示在nnn個中選偶數個的方案數

考慮把nnn分成前后各一半

Ⅰ設n/2n/2n/2為奇數

T(n,1)=T(n/2,1)?T(n/2,0)+T(n/2,0)?T(n/2,1)=2?T(n/2,0)?T(n/2,1)T(n,1)=T(n/2,1)*T(n/2,0)+T(n/2,0)*T(n/2,1)=2*T(n/2,0)*T(n/2,1)T(n,1)=T(n/2,1)?T(n/2,0)+T(n/2,0)?T(n/2,1)=2?T(n/2,0)?T(n/2,1)

T(n,0)=T(n/2,1)?T(n/2,1)+T(n/2,0)?T(n/2,0)T(n,0)=T(n/2,1)*T(n/2,1)+T(n/2,0)*T(n/2,0)T(n,0)=T(n/2,1)?T(n/2,1)+T(n/2,0)?T(n/2,0)

先前證明過當xxx為奇數時,其選擇奇數和偶數的方案數相等

T(n,0)=T(n/2,1)?T(n/2,0)+T(n/2,0)?T(n/2,1)=2?T(n/2,0)?T(n/2,1)T(n,0)=T(n/2,1)*T(n/2,0)+T(n/2,0)*T(n/2,1)=2*T(n/2,0)*T(n/2,1)T(n,0)=T(n/2,1)?T(n/2,0)+T(n/2,0)?T(n/2,1)=2?T(n/2,0)?T(n/2,1)

?T(n,0)=T(n,1)\Rightarrow T(n,0)=T(n,1)?T(n,0)=T(n,1)

Ⅱ設n/2n/2n/2為偶數

遞歸n/2n/2n/2,不停的除以222,總有一層是奇數,就變成了Ⅰ

證畢


大力討論列出轉移方程

①點i+1i+1i+1為白色,且endendend為偶數,總和奇偶性不變
f[i+1][j][k][h]=f[i][j][k][h]?2k?1?2i?kf[i+1][j][k][h]=f[i][j][k][h]*2^{k-1}*2^{i-k}f[i+1][j][k][h]=f[i][j][k][h]?2k?1?2i?k

2k?12^{k-1}2k?1:會對i+1i+1i+1奇偶性造成影響的kkk個黑色奇數點,從中選擇奇數個的方案數,endi+1end_{i+1}endi+1?有這些黑色奇數點帶來的奇數貢獻,再加上自己到自己本身一條路徑,就是偶數了

2i?k2^{i-k}2i?k:剩下的點與i+1i+1i+1可連可不連,不會造成影響

②點i+1i+1i+1為白色,且endendend為奇數,總和奇偶改變
f[i+1][j+1][k][h?1]=f[i][j][k][h]?2k?1?2i?kf[i+1][j+1][k][h\bigoplus1]=f[i][j][k][h]*2^{k-1}*2^{i-k}f[i+1][j+1][k][h?1]=f[i][j][k][h]?2k?1?2i?k

2k?12^{k-1}2k?1:會對i+1i+1i+1奇偶性造成影響的kkk個黑色奇數點,從中選擇偶數個的方案數

③點i+1i+1i+1為黑色,且endendend為偶數,總和奇偶性不變
f[i+1][j][k][h]=h[i][j][k][h]?2j?1?2i?jf[i+1][j][k][h]=h[i][j][k][h]*2^{j-1}*2^{i-j}f[i+1][j][k][h]=h[i][j][k][h]?2j?1?2i?j

2j?12^{j-1}2j?1:會對i+1i+1i+1奇偶性造成影響的jjj個白色奇數點,從中選擇奇數個的方案數

④點i+1i+1i+1為黑色,且endendend為奇數,總和奇偶改變
f[i+1][j][k+1][h?1]=f[i][j][k][h]?2j?1?2i?jf[i+1][j][k+1][h\bigoplus 1]=f[i][j][k][h]*2^{j-1}*2^{i-j}f[i+1][j][k+1][h?1]=f[i][j][k][h]?2j?1?2i?j

2j?12^{j-1}2j?1:會對i+1i+1i+1奇偶性造成影響的jjj個白色奇數點,從中選擇偶數個的方案數

如果點i+1i+1i+1被欽定為黑色,則沒有①②的轉移;白色則沒有③④的轉移

觀察到每個轉移方程中后面兩個222的冪乘積與j,kj,kj,k無關,都為2i?12^{i-1}2i?1
j,kj,kj,k000時,從中選偶數個為2i2^i2i,選奇數個為000

于是,不再需要j,kj,kj,k的實際值了

f[i][0/1][0/1][h]f[i][0/1][0/1][h]f[i][0/1][0/1][h],表示前iii個點,endendend和的奇偶為hhh,是否有endendend為奇數的白/黑點

#include <cstdio> #define int long long #define mod 998244353 #define maxn 200005 int f[maxn][2][2][2]; int mi[maxn], c[maxn]; int n;signed main() {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &c[i] );mi[0] = 1;for( int i = 1;i <= n;i ++ ) mi[i] = ( mi[i - 1] << 1 ) % mod;f[0][0][0][0] = 1;for( int i = 0;i < n;i ++ )for( int j = 0;j <= 1;j ++ )for( int k = 0;k <= 1;k ++ )for( int h = 0;h <= 1;h ++ ) {if( ! f[i][j][k][h] ) continue;if( c[i + 1] != 1 ) {f[i + 1][j][k][h] = ( f[i + 1][j][k][h] + f[i][j][k][h] * ( k ? mi[i - 1] : 0 ) % mod ) % mod;f[i + 1][j | 1][k][h ^ 1] = ( f[i + 1][j | 1][k][h ^ 1] + f[i][j][k][h] * ( k ? mi[i - 1] : mi[i] ) % mod ) % mod;}if( c[i + 1] != 0 ) {f[i + 1][j][k][h] = ( f[i + 1][j][k][h] + f[i][j][k][h] * ( j ? mi[i - 1] : 0 ) % mod ) % mod;f[i + 1][j][k | 1][h ^ 1] = ( f[i + 1][j][k | 1][h ^ 1] + f[i][j][k][h] * ( j ? mi[i - 1] : mi[i] ) % mod ) % mod;}}int ans = 0;for( int j = 0;j <= 1;j ++ )for( int k = 0;k <= 1;k ++ )ans = ( ans + f[n][j][k][1] ) % mod;printf( "%lld\n", ans );return 0; }

贏家

n≤15,m≤n×(n+1)2n\le 15,m\le \frac{n\times (n+1)}{2}n15,m2n×(n+1)?


轉化為用總數2m2^m2m減去不合法的方案數

不合法方案數即為,111能到達的點集SSS222能到達的點集為TTTS∩T=?S∩T=\emptysetST=?

f[S]f[S]f[S]表示能使111到達點集為SSS內所有點的方案數,g[T]g[T]g[T]為能使222到達點集為TTT內所有點的方案數

枚舉S,TS,TS,T,兩個集合內部的邊的定向方案數即為f[S]×g[T]f[S]\times g[T]f[S]×g[T](不能有邊跨越S,TS,TS,T

對于點集S∪TS∪TST的補集中的點,內部邊可以隨便定向2edge2^{edge}2edge,而對于一個頂點在集合外另一個頂點在S,TS,TS,T集合內的邊,一定是從集合外指向集合內

枚舉的時間復雜度為O(3n)O(3^n)O(3n)

接下來考慮怎么計算f[S]f[S]f[S]g[T]g[T]g[T]與之一樣

一樣的思路,用總數減去不合法的數量

總數為2edge_S2^{edge\_S}2edge_S

減去不合法的方案,枚舉一個SSS的真子集s′s's,計算只能到達子集s′s's內的點的方案數

點集s’s’s內的方案數為f[s′]f[s']f[s],點集外的方案數為2edge_S?edge_s’2^{edge\_S-edge\_s’}2edge_S?edge_s

對于橫跨s’,CSs′s’,C_{S}s's,CS?s的邊,方向一定是從外面指向子集s′s's

所以此時減去的方案數為f[s′]×2edge_S?edge_s′f[s']\times 2^{edge\_S-edge\_s'}f[s]×2edge_S?edge_s

枚舉子集,DPDPDP時間復雜度為O(3n)O(3^n)O(3n)

#include <cstdio> #define mod 1000000007 #define int long long #define maxn 20 #define maxm 1 << 15 int n, m, id; bool edge[maxn][maxn]; int in[maxm], out[maxm], mi[maxn * maxn], f[maxm], g[maxm];signed main() {scanf( "%lld %lld %lld", &n, &m, &id );mi[0] = 1;for( int i = 1, u, v;i <= m;i ++ ) {scanf( "%lld %lld", &u, &v );edge[u][v] = 1;mi[i] = ( mi[i - 1] << 1 ) % mod;}int cnt = 1 << n;for( int S = 0;S < cnt;S ++ )for( int i = 1;i <= n;i ++ )for( int j = 1;j <= n;j ++ )if( edge[i][j] ) {if( ( 1 << i - 1 & S ) && ( 1 << j - 1 & S ) ) in[S] ++;//完全包含在點集S里面的邊if( ( 1 << i - 1 & S ) || ( 1 << j - 1 & S ) ) out[S] ++;//完全包含在點集S里面的邊+一個頂點在點集里一個頂點在點集外}for( int S = 0;S < cnt;S ++ ) {if( ! ( S & 1 ) ) continue;//如果沒有包含點1 跳過f[S] = mi[in[S]];for( int T = ( S - 1 ) & S;T;T = ( T - 1 ) & S ) {if( ! ( T & 1 ) ) continue;//子集也必須包含點1f[S] = ( f[S] - f[T] * mi[in[S ^ T]] % mod + mod ) % mod;}}for( int S = 0;S < cnt;S ++ ) {if( ! ( S >> 1 & 1 ) ) continue;g[S] = mi[in[S]];for( int T = ( S - 1 ) & S;T;T = ( T - 1 ) & S ) {if( ! ( T >> 1 & 1 ) ) continue;g[S] = ( g[S] - g[T] * mi[in[S ^ T]] % mod + mod ) % mod;}}int ans = mi[m];for( int S = 0;S < cnt;S ++ ) { if( ! ( S & 1 ) || ( S >> 1 & 1 ) ) continue;for( int T = ( cnt - 1 ) ^ S;T;T = ( T - 1 ) & ( ( cnt - 1 ) ^ S ) ) {if( ! ( T >> 1 & 1 ) || in[S] + in[T] < in[S | T] ) continue;//如果沒有包含點2 或 S,T點集有邊橫跨兩個集合 為不合法劃分 跳過ans = ( ans - f[S] * g[T] % mod * mi[m - out[S | T]] % mod + mod ) % mod;}}printf( "%lld\n", ans );return 0; }

黑紅兔

n≤5e5n\le 5e5n5e5


性質1:存在一種方案,最后一段長度為111,每選出的段的長度都比上一段小111

很顯然,如果某一段比下一段長≥2\ge 22,可以在前面或者后面去掉若干字符,只需要保證下一段是嚴格子串即可

f[i][j]f[i][j]f[i][j]表示以子串[i,j][i,j][i,j]為首串,能否找出j?i+1j-i+1j?i+1段符合要求

fffyes/noyes/noyes/noboolboolbool數組

枚舉下一段與f[i+1,j]f[i+1,j]f[i+1,j]還是f[i][j?1]f[i][j-1]f[i][j?1]進行轉移

hashhashhash判斷兩個串是否相同

性質2:答案不超過O(n)O(\sqrt{n})O(n?)

最好的情況為1+2+...+k1+2+...+k1+2+...+k,此時有k(k+1)2≤n\frac{k(k+1)}{2}\le n2k(k+1)?n

性質3:假設以iii作為第一段開頭,如果第一個串長lenlenlen時,可以選出lenlenlen段,那么串長為len?1len-1len?1時,也能選出len?1len-1len?1

非常顯然,都刪去一個首/尾跟下一段無關的字符,最后一段被刪去,仍能保證嚴格子串性質

f[i]f[i]f[i]為以iii開始的首串,最長能選多少段

考慮二分答案,問題轉化為找[i+mid,n][i+mid,n][i+mid,n]內是否存在一個jjj,滿足

f[j]≥mid?1f[j]\ge mid-1f[j]mid?1

lcp(i,j)≥mid?1lcp(i,j)\ge mid-1lcp(i,j)mid?1或者lcp(i+1,j)≥mid?1lcp(i+1,j)\ge mid-1lcp(i+1,j)mid?1(看是首/尾是新添的多余字符

如果求出原串的后綴數組,那么lcp(i,j)≥xlcp(i,j)\ge xlcp(i,j)x相當于rnkjrnk_jrnkj?在某個區間內,可以二分求出這個區間

此套路做法,詳情可見👉親愛的佳媛姐姐正解做法——字符串LOJ2059

O(nlog2n)O(nlog^2n)O(nlog2n)

性質4:f[i]≤f[i+1]+1f[i]\le f[i+1]+1f[i]f[i+1]+1

如果iii開始能接大于f[i+1]+1f[i+1]+1f[i+1]+1段,那么i+1i+1i+1開始一定能接大于f[i+1]+1?1=f[i+1]f[i+1]+1-1=f[i+1]f[i+1]+1?1=f[i+1]段,有性質3得出

所以就不用二分了,類似滑動窗口一樣,先把f[i]f[i]f[i]賦為f[i+1]+1f[i+1]+1f[i+1]+1,然后判斷是否可行,不行就一直?1-1?1直到可行為止

類似于SASASAheightheightheight數組,O(nlogn)O(nlogn)O(nlogn)

預處理ststst表里面的logloglog,快了整整三秒,卡(>ρ<")了

終于過了(^U^)ノ~YO

#include <cstdio> #include <cstring> #include <iostream> using namespace std; #define maxn 500005 #define INF 0x7f7f7f7f int n, m = 255; char s[maxn]; int tot[maxn], rnk[maxn << 1], sa[maxn], id[maxn], x[maxn], h[maxn], lg[maxn]; int st[maxn][20];void init() {for( int i = 1;i <= n;i ++ ) tot[x[i] = s[i]] ++;for( int i = 1;i <= m;i ++ ) tot[i] += tot[i - 1];for( int i = n;i;i -- ) sa[tot[x[i]] --] = i;for( int k = 1;k <= n;k <<= 1 ) {int num = 0;for( int i = n - k + 1;i <= n;i ++ ) id[++ num] = i;for( int i = 1;i <= n;i ++ ) if( k < sa[i] ) id[++ num] = sa[i] - k;memset( tot, 0, sizeof( tot ) );for( int i = 1;i <= n;i ++ ) tot[x[i]] ++;for( int i = 1;i <= m;i ++ ) tot[i] += tot[i - 1];for( int i = n;i;i -- ) sa[tot[x[id[i]]] --] = id[i];for( int i = 1;i <= n;i ++ ) rnk[i] = x[i];x[sa[1]] = num = 1;for( int i = 2;i <= n;i ++ )x[sa[i]] = ( rnk[sa[i]] == rnk[sa[i - 1]] && rnk[sa[i] + k] == rnk[sa[i - 1] + k] ) ? num : ++ num;if( n == num ) break;m = num;}for( int i = 1;i <= n;i ++ ) rnk[sa[i]] = i;int k = 0;for( int i = 1;i <= n;i ++ ) {if( rnk[i] == 1 ) continue;if( k ) k --;int j = sa[rnk[i] - 1];while( i + k <= n && j + k <= n && s[i + k] == s[j + k] ) k ++;h[rnk[i]] = k;}lg[0] = -1;for( int i = 1;i <= n;i ++ ) lg[i] = lg[i >> 1] + 1;for( int i = 1;i <= n;i ++ ) st[i][0] = h[i];for( int j = 1;j <= 18;j ++ )for( int i = 1;i <= n;i ++ )if( i + ( 1 << j - 1 ) > n ) break;else st[i][j] = min( st[i][j - 1], st[i + ( 1 << j - 1 )][j - 1] ); }int lcp( int l, int r ) {int i = lg[r - l + 1];return min( st[l][i], st[r - ( 1 << i ) + 1][i] ); }int cnt; int rt[maxn], t[maxn * 30], lson[maxn * 30], rson[maxn * 30];void modify( int pre, int &now, int l, int r, int pos, int val ) {if( ! now ) now = ++ cnt;if( l == r ) { t[now] = max( t[now], val ); return; }int mid = ( l + r ) >> 1;if( pos <= mid ) rson[now] = rson[pre], modify( lson[pre], lson[now], l, mid, pos, val );else lson[now] = lson[pre], modify( rson[pre], rson[now], mid + 1, r, pos, val );t[now] = max( t[lson[now]], t[rson[now]] ); }int query( int now, int l, int r, int L, int R ) {if( ! now || R < l || r < L ) return 0;if( L <= l && r <= R ) return t[now];int mid = ( l + r ) >> 1;return max( query( lson[now], l, mid, L, R ), query( rson[now], mid + 1, r, L, R ) ); }int find_l( int pos, int len ) {int l = 1, r = pos - 1;while( l <= r ) {int mid = ( l + r ) >> 1;if( lcp( mid + 1, pos ) >= len ) r = mid - 1;else l = mid + 1;}return l; }int find_r( int pos, int len ) {int l = pos + 1, r = n;while( l <= r ) {int mid = ( l + r ) >> 1;if( lcp( pos + 1, mid ) >= len ) l = mid + 1;else r = mid - 1;}return r; }bool check( int pos, int len ) {if( query( rt[pos + len], 1, n, find_l( rnk[pos], len - 1 ), find_r( rnk[pos], len - 1 ) ) >= len - 1 )return 1;if( query( rt[pos + len], 1, n, find_l( rnk[pos + 1], len - 1 ), find_r( rnk[pos + 1], len - 1 ) ) >= len - 1 )return 1;return 0; }int ans; int f[maxn];int main() {scanf( "%s", s + 1 );n = strlen( s + 1 ); init();ans = f[n] = 1;modify( rt[n + 1], rt[n], 1, n, rnk[n], f[n] );for( int i = n - 1;i;i -- ) {f[i] = f[i + 1] + 1;while( ! check( i, f[i] ) ) f[i] --;ans = max( ans, f[i] );modify( rt[i + 1], rt[i], 1, n, rnk[i], f[i] );}printf( "%d\n", ans );return 0; }

總結

以上是生活随笔為你收集整理的test 7 3-22 2021省选模拟赛seven的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。