生活随笔
收集整理的這篇文章主要介紹了
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 省选模拟赛(灯,十字路口,密室逃脱)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。