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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

2021-4-4 省选模拟赛(灯,十字路口,密室逃脱)

發布時間:2023/12/3 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 2021-4-4 省选模拟赛(灯,十字路口,密室逃脱) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 考試復盤
  • A:燈(light)
  • B:十字路口(crossing)
  • C:密室逃脫(escape)

考試復盤

第一題分塊雖然明顯,但是說實話自己沒怎么做過分塊的題
就不會做大塊的處理。。。(;?_?)
今天聽H老說分塊可以成替代數據結構的騙分暴力對拍神器
這么一聽似乎非常有用,今晚要刷一刷了!!
但是我的暴力竟然又掛了!!(*゚Д゚)つミ匚___

第二題沒有反應過來這個周期其實相當于是找環,暴力判的,額,結果不言而喻

第三題雖然也看得出來是DPDPDP,但是那個轉移方程式確實不可能是我的實力想得到的嚶嚶嚶~~
一般這種有時間關卡的們,隧道等等這種在一條“路”上的1?n1-n1?n問題一般都是考察的DPDPDP,貪心,轉化為最短路等圖論問題,最多來個線段樹分治

今天的題目總的來說,考什么算法是非常顯而易見的,但是細節以及實現卻成為了難點
大綱清晰考察刁鉆,千言萬語只能化作一句好!很好!非常好!


A:燈(light)

分塊
連續段數等于開著的燈數減相鄰兩個都開著的燈對數
次數<n<\sqrt{n}<n?的顏色,直接暴力枚舉所在位置更新
次數>n>\sqrt{n}>n?的顏色,維護與這種顏色相鄰的開著的燈數
每次我們改變>n>\sqrt{n}>n?的顏色時,直接用這個算答案

#include <map> #include <cmath> #include <cstdio> #include <vector> #include <algorithm> using namespace std; #define Pair pair < int, int > #define maxn 100005 #define Block 350 vector < int > pos[maxn]; int n, m, Q, ans; int c[maxn], cnt[maxn], t[maxn], big[Block], MS[maxn]; int g[Block][Block]; bool vis[maxn];int main() {freopen( "light.in", "r", stdin );freopen( "light.out", "w", stdout );scanf( "%d %d %d", &n, &m, &Q );for( int i = 1;i <= n;i ++ ) {scanf( "%d", &c[i] );if( c[i] == c[i - 1] ) i --, n --;else;}for( int i = 0;i <= n;i ++ ) {pos[c[i]].push_back( i ); cnt[c[i]] ++;}int block = sqrt( n ), ip = 0;for( int i = 1;i <= m;i ++ )if( cnt[i] > block ) big[++ ip] = i, MS[i] = ip;else;for( int i = 1;i < n;i ++ )g[MS[c[i]]][MS[c[i + 1]]] ++, g[MS[c[i + 1]]][MS[c[i]]] ++;while( Q -- ) {int x;scanf( "%d", &x );if( vis[x] ) {ans -= cnt[x];if( MS[x] ) {ans += t[x];for( int i = 1;i <= ip;i ++ )if( vis[big[i]] ) ans += g[i][MS[x]];else;}else {for( int i = 0;i < pos[x].size();i ++ ) {ans += vis[c[pos[x][i] - 1]];ans += vis[c[pos[x][i] + 1]];t[c[pos[x][i] - 1]] --;t[c[pos[x][i] + 1]] --;}}}else {ans += cnt[x];if( MS[x] ) {ans -= t[x];for( int i = 1;i <= ip;i ++ )if( vis[big[i]] ) ans -= g[i][MS[x]];else;}else {for( int i = 0;i < pos[x].size();i ++ ) {ans -= vis[c[pos[x][i] - 1]];ans -= vis[c[pos[x][i] + 1]];t[c[pos[x][i] - 1]] ++;t[c[pos[x][i] + 1]] ++;}}}vis[x] ^= 1;printf( "%d\n", ans );}return 0; }

B:十字路口(crossing)



xix_ixi?表示第iii次觀察的時間(對周期取模)
如果有一個燈在兩次觀察中都是紅燈,可以得到一個形如xi?xj=kx_i-x_j=kxi??xj?=k的方程
將這看做是iii指向jjj權值為kkk的有向邊,那么一個環的長度顯然是周期的倍數
不難證明最小環就是周期,用floydfloydfloyd求出,時間復雜度為O(m3+nm2)O(m^3+nm^2)O(m3+nm2)
同理設yiy_iyi?表示第iii個燈由紅變綠的時間,一樣的方法,時間復雜度為O(n3+mn2)O(n^3+mn^2)O(n3+mn2)
結合兩種方法可以做到O(nmnm)O(nm\sqrt{nm})O(nmnm?),哪個小用哪種

#include <cstdio> #include <vector> #include <cstring> using namespace std; #define maxn 400 #define maxm 100005 #define inf 0x3f3f3f3f vector < int > G[maxm]; int n, m; int dis[maxn][maxn];int main() {freopen( "crossing.in", "r", stdin );freopen( "crossing.out", "w", stdout );scanf( "%d %d", &n, &m );for( int i = 1;i <= m;i ++ )G[i].resize( n );for( int i = 1;i <= m;i ++ )for( int j = 0;j < n;j ++ )scanf( "%d", &G[i][j] );memset( dis, 0x3f, sizeof( dis ) );int ans = inf;if( m <= n ) {for( int i = 1;i <= m;i ++ )for( int k = i + 1;k <= m;k ++ )for( int j = 0;j < n;j ++ )if( G[i][j] && G[k][j] ) {if( G[i][j] > G[k][j] )dis[i][k] = G[i][j] - G[k][j];elsedis[k][i] = G[k][j] - G[i][j];}else;for( int k = 1;k <= m;k ++ )for( int i = 1;i <= m;i ++ )for( int j = 1;j <= m;j ++ )dis[i][j] = min( dis[i][j], dis[i][k] + dis[k][j] );for( int i = 1;i <= m;i ++ )ans = min( ans, dis[i][i] );}else {for( int j = 0;j < n;j ++ )for( int k = j + 1;k < n;k ++ )for( int i = 1;i <= m;i ++ )if( G[i][j] && G[i][k] ) {if( G[i][j] > G[i][k] )dis[j][k] = G[i][j] - G[i][k];elsedis[k][j] = G[i][k] - G[i][j];}else;for( int k = 0;k < n;k ++ )for( int i = 0;i < n;i ++ )for( int j = 0;j < n;j ++ )dis[i][j] = min( dis[i][j], dis[i][k] + dis[k][j] );for( int i = 0;i < n;i ++ )ans = min( ans, dis[i][i] );}if( ans == inf ) printf( "-1\n" );else printf( "%d\n", ans );return 0; }

C:密室逃脫(escape)


#include <cstdio> #include <iostream> using namespace std; #define Edge 20000 #define maxn 1005 int n, m; int a[maxn], b[maxn]; int dp[maxn][Edge + 5];int main() {freopen( "escape.in", "r", stdin );freopen( "escape.out", "w", stdout );scanf( "%d %d", &n, &m );for( int i = 1;i < n;i ++ )scanf( "%d %d", &a[i], &b[i] );for( int i = 0;i < m;i ++ ) dp[1][i] = i;for( int i = 1;i < n;i ++ ) {int maxx = 0;for( int j = 0;j < a[i];j ++ ) {dp[i + 1][j + b[i]] = max( dp[i + 1][j + b[i]], dp[i][j] + b[i] );maxx = max( maxx, dp[i][j] );}for( int j = 0;j < b[i];j ++ )dp[i + 1][j] = max( dp[i + 1][j], maxx + j );for( int j = a[i];j < a[i] + b[i];j ++ )dp[i + 1][j - a[i]] = max( dp[i + 1][j - a[i]], dp[i][j] );for( int j = a[i] + b[i];j <= Edge;j ++ )dp[i + 1][j] = max( dp[i + 1][j], dp[i][j] );}int ans = 0;for( int i = 0;i <= Edge;i ++ )ans = max( ans, dp[n][i] );printf( "%d\n", ans );return 0; }

總結

以上是生活随笔為你收集整理的2021-4-4 省选模拟赛(灯,十字路口,密室逃脱)的全部內容,希望文章能夠幫你解決所遇到的問題。

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