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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

test1 3-15 模拟赛1

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

文章目錄

  • 考試復盤
  • matrix
  • set
  • string

考試復盤


首先先說T1T1T1,嗯,發現了列是相互獨立的,所以分開考慮了
但是實在沒想到線性基,就順著自己的思路硬搞了505050跑路
老實說,505050分的部分分寫得都是迷迷糊糊的,重構了好幾遍
幸好過了,不然自己今天就是個圓溜的零光蛋了

沒想到的點:

  • 線性基
  • 二進制的加法可以轉化為異或
  • bitset優化

  • 再說T2T2T2,嗯——怎么說呢
    想到了枚舉最小值,然后線段樹找符合的區間[val,val?2)[val,val*2)[val,val?2)
    然后想到了三維的過原點立方體
    就不會了—— ,主要是之前沒碰到過,只做過二維的可以用setsetset整活
    這次遇到了,積累!!
    幸好有202020的兩種顏色數據
    可是我還是沒拿到
    因為忘記減去(0,0,0)(0,0,0)(0,0,0)三元組情況

    發生這種過失性丟分的唯一原因就是沒有好好分析樣例
    給自己敲個警鐘!!!

    沒想到的點:

  • 掃描線
  • 線段樹維護二維
  • 注意的點:

  • 仔細分析樣例

  • 最后說一下T3T3T3
    其實很長一段時間是沒有看懂題面的
    樣例也想不懂
    是中午吃飯的時候去操場逛了兩圈,才想懂了樣例題面的意思
    回來匆匆敲個暴力,還沒過樣例,害~

    沒想到的點:

  • 后綴數組
  • 同構字符串的轉化——真的學到了!!
  • 不過必須表揚自己認真磕出了樣例
    那為毛不磕一下T2T2T2的樣例!!想穿越回去抽自己


    說一下今天考試的自我感受

  • 樹立了自信心,因為整體來看自己對這套題目的正確性應該是有50%50\%50%的,省選并沒有自己想象得那么恐怖
  • 可以說這一場考試,是有史以來最認真的了,從頭到尾都在努力思考,第一次寫滿了整整一張的思路推理驗算,也發現其實在自己一步步的推演下,正解仿佛就只隔了一個教室而已,hhhh
  • 真的跟著學長們一起,會有那種學習認真的氛圍,而且今天確實學到了很多,也覺得他們和自己同班的同學都很強,自己也要繼續努力!!!

  • matrix


    在二進制下,加法等價于異或

    ∑k=1nA[i][k]×C[k][j]\sum_{k=1}^nA[i][k]\times C[k][j]k=1n?A[i][k]×C[k][j]

    ∑k∈SC[k][j]=B[i][j]×C[i][j]\sum_{k∈S}C[k][j]=B[i][j]\times C[i][j]kS?C[k][j]=B[i][j]×C[i][j]

    都是第jjj列,說明每列是相互獨立的,那么單獨考慮每一列,統計答案時把所有列的方案數乘起來即可

    B[i][j]=0B[i][j]=0B[i][j]=0,則等式右邊為000

    B[i][j]=1B[i][j]=1B[i][j]=1,則等式右邊為C[i][j]C[i][j]C[i][j]

    因為是異或,所以兩邊都可以再異或上C[i][j]C[i][j]C[i][j]

    ∑k∈S′C[k][j]=0\sum_{k∈S'}C[k][j]=0kS?C[k][j]=0
    **這里尚有問題,提醒自己一下

    #include <cstdio> #include <bitset> using namespace std; #define maxn 205 #define mod 998244353 int n, cnt, ans = 1; int A[maxn][maxn], B[maxn][maxn]; bitset < maxn > lib[maxn], t;int qkpow( int x, int y ) {int res = 1;while( y ) {if( y & 1 ) res = 1ll * res * x % mod;x = 1ll * x * x % mod;y >>= 1;}return res; }int main() {scanf( "%d", &n );for( int i = 1;i <= n;i ++ )for( int j = 1;j <= n;j ++ )scanf( "%d", &A[i][j] );for( int i = 1;i <= n;i ++ )for( int j = 1;j <= n;j ++ )scanf( "%d", &B[i][j] );for( int j = 1;j <= n;j ++ ) {for( int i = 1;i <= n;i ++ )lib[i].reset();cnt = 0;for( int i = 1;i <= n;i ++ ) {t.reset();for( int k = 1;k <= n;k ++ )if( A[i][k] ) t.flip( k );if( B[i][j] ) t.flip( i );for( int k = 1;k <= n;k ++ )if( t[k] ) {if( lib[k].any() ) t ^= lib[k];else {lib[k] = t;cnt++;break;}}}ans += n - cnt;}ans = qkpow( 2, ans );printf( "%lld\n", ans );return 0; }

    set


    枚舉所選集合中最小的權值,forforfor循環掃一遍求出[val,val?2)[val,val*2)[val,val?2) 里所有的物品,這些都是可選的

    對于求出的數量用三元組表示r,g,br,g,br,g,b 那么每一種顏色的選擇都是[0,r],[0,g],[0,b][0,r],[0,g],[0,b][0,r],[0,g],[0,b]

    放在三維坐標里,就是求過原點的一個立方體的體積

    考試的時候就只想到了立方體,發現自己只會平面的,所以這道題敲不來

    用掃描線維護一維rrr

    具體來說就是對于三元組(r,g,b)(r,g,b)(r,g,b)rrr時刻將(g,b)(g,b)(g,b)插進去

    從大到小計算

    因為在rrr時刻的(g,b)(g,b)(g,b)二元組,一定在r?1r-1r?1時刻也是正確的

    從小到大,有的二元組會涉及到刪除,對于蒟蒻來說不好做,因為我掃描線就很困難了好吧

    剩下兩維的平面直角坐標系計算圍成的面積,以前做過這種題

    setsetset或者線段樹都可以做

    #include <cstdio> #include <vector> #include <iostream> #include <algorithm> using namespace std; #define maxn 500005 struct node {int val, c;node(){}node( int Val, int C ) {val = Val, c = C;} }v[maxn]; vector < pair < int, int > > G[maxn]; int n; int tot[3]; long long tree[maxn << 2], tag[maxn << 2], maxx[maxn << 2];bool cmp( node x, node y ) {return x.val < y.val; } int id( char c ) {if( c == 'R' ) return 0;if( c == 'G' ) return 1;if( c == 'B' ) return 2; }void pushdown( int num, int l, int r ) {if( tag[num] ) {maxx[num << 1] = tag[num << 1] = tag[num];maxx[num << 1 |1] = tag[num << 1 | 1] = tag[num];int mid = ( l + r ) >> 1;tree[num << 1] = tag[num] * ( mid - l + 1 );tree[num << 1 | 1] = tag[num] * ( r - mid );tag[num] = 0;} }void modify( int num, int l, int r, int L, int R, int val ) {if( L <= l && r <= R && maxx[num] < val ) {tree[num] = 1ll * val * ( r - l + 1 );maxx[num] = tag[num] = val;return;}if( l == r ) return;int mid = ( l + r ) >> 1;pushdown( num, l, r );if( L <= mid && maxx[num << 1 | 1] < val )//如果是被完全包含的面積是不進行計算的 這里可以多想想modify( num << 1, l, mid, L, R, val );if( mid < R )modify( num << 1 | 1, mid + 1, r, L, R, val );tree[num] = tree[num << 1] + tree[num << 1 | 1];maxx[num] = max( maxx[num << 1], maxx[num << 1 | 1] ); }int main() {scanf( "%d", &n );int x; char color[3];for( int i = 1;i <= n;i ++ ) {scanf( "%d %s", &x, color );v[i] = node( x, id( color[0] ) );}sort( v + 1, v + n + 1, cmp );G[0].push_back( make_pair( 0, 0 ) );int j = 1;for( int i = 1;i <= n;i ++ ) {while( j <= n && v[j].val < ( v[i].val << 1 ) )tot[v[j].c] ++, j ++;G[tot[0]].push_back( make_pair( tot[1], tot[2] ) );tot[v[i].c] --;}long long ans = 0;for( int i = n;~ i;i -- ) {//掃描線去掉一維 相當于切立方體的厚度 切成厚度為1的多個面狀for( int j = 0;j < G[i].size();j ++ )modify( 1, 0, n, 0, G[i][j].first, G[i][j].second + 1 ); //加1是因為這個面積是和原點相圍成的 畫畫圖會發現其實需要列拔高一層ans += tree[1];}printf( "%lld", ans - 1 );//不算(0,0,0)return 0; }

    string


    對于一個字符串,將第一次新出現的字符設為000,其余位置賦值為該位置減去上一次字符出現的位置

    這樣的轉化就將同構字符串改寫成完全相同的數字串了

    這里真的太巧妙了,第一次遇到,記下來!!!

    求本質不同的子串就是后綴數組的基礎了

    所有子串長度?-?heightheightheight數組之和

    但是!!

    題目是處理子串之間的問題

    那么就有子串的改寫會與原串的改寫有出入的問題

    就是說子串中第一次出現的某個字符不一定是原串整個串中第一次出現

    那么子串該位置就需要修改為000

    一共只有262626個字符,所以子串最多只會有262626個位置與原串不一樣

    可以人為暴力排序

    將一段根據修改的000劃分成若干段

    兩個子串的cmpcmpcmp比較,如果是相同的部分就用原串的后綴數組sasasa搞定,更改過的地方就暴力比較

    總結一下,代碼實現思路

  • 對原串改寫
  • 對原串后綴數組
  • 利用原串的后綴數組再次暴力排序后綴
  • 求出按照新規定下排好的后綴之間的lcplcplcp之和
  • 子串總長度減去lcplcplcp之和
  • #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 100005struct node {int n, m;int x[maxn], id[maxn], rnk[maxn << 1], h[maxn], sa[maxn], tot[maxn];int st[maxn][20];void suffix( int N, int *s ) {n = N, m = N + 1;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( sa[i] > k ) 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;}for( int i = 1;i <= n;i ++ ) st[i][0] = h[i];for( int j = 1;j < 20;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 ) {if( l <= 0 || r <= 0 || l > n || r > n ) return 0;if( l == r ) return n - l + 1;l = rnk[l], r = rnk[r];if( l > r ) swap( l, r );l ++;int i = log( r - l + 1 ) / log( 2 );return min( st[l][i], st[r - ( 1 << i ) + 1][i] );}}SA; int n; char s[maxn]; int last[maxn], idx[maxn], t[maxn]; int nxt[maxn][30];int LCP( int x, int y ) {int sx = x, sy = y;x --, y --;int len = 0;for( int i = 0;i < 26 && x + 1 <= n && y + 1 <= n;i ++ ) {int l = SA.lcp( x + 1, y + 1 );if( x + l + 1 < nxt[sx][i] && y + l + 1 < nxt[sy][i] ) return len + l;if( nxt[sx][i] - sx == nxt[sy][i] - sy ) {//如果一段都是相同 就一段段的跳len += nxt[sx][i] - x;x = nxt[sx][i], y = nxt[sy][i];}else {if( nxt[sx][i] - sx < nxt[sy][i] - sy )return len + nxt[sx][i] - x - 1;elsereturn len + nxt[sy][i] - y - 1;}}return len; }bool cmp( int x, int y ) {int len = LCP( x, y );if( x + len > n || y + len > n ) return x + len > n;int vx = t[x + len], vy = t[y + len];for( int i = 0;i < 26;i ++ )if( nxt[x][i] == x + len ) { vx = 0; break; }for( int i = 0;i < 26;i ++ )if( nxt[y][i] == y + len ) { vy = 0; break; }return vx < vy; }int main() {scanf( "%d %s", &n, s + 1 );for( int i = 1;i <= n;i ++ ) {int j = s[i] - 'a';if( ! last[j] ) t[i] = n + 1;else t[i] = i - last[j];last[j] = i, idx[i] = i;}SA.suffix( n, t );for( int i = 0;i < 26;i ++ ) nxt[n + 1][i] = n + 2;for( int i = n;i;i -- ) {for( int j = 0;j < 26;j ++ )nxt[i][j] = nxt[i + 1][j];nxt[i][s[i] - 'a'] = i;}for( int i = 1;i <= n;i ++ )sort( nxt[i], nxt[i] + 26 );sort( idx + 1, idx + n + 1, cmp );long long ans = 1ll * n * ( n + 1 ) / 2;for( int i = 1;i < n;i ++ )ans -= LCP( idx[i], idx[i + 1] );printf( "%lld\n", ans );return 0; }

    后記:大概會在周末進行再次復盤,重新消化吸收,順便看看到時候自己是否會將好不容易轉操場想懂的地方又搞懵
    走了回家睡覺,現在時間2021/3/15 22:48

    總結

    以上是生活随笔為你收集整理的test1 3-15 模拟赛1的全部內容,希望文章能夠幫你解決所遇到的問題。

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