为什么每次想的最久的题得的分数最低!!!qwqwq
再也不在noip上尝试A*叻!!
模拟题,先把能消的消掉,双指针从两端向中间扫描,如果头尾合并可以消,就把它消掉,最后判断一下。因为消完过后num保留的是中间的个数,要把两端加上(实际就是一个循环节的长度
#include<iostream> #include<cstdio> #define ll long long using namespace std; ll n, m, k, a[100005]; ll color[100005], num[100005], cnt, tot; int main ( ) { freopen ( "guass.in", "r", stdin ); freopen ( "guass.out", "w", stdout ); scanf ( "%I64d%I64d%I64d", &n, &m, &k ); for ( int i = 1; i <= n; i ++ ) { scanf ( "%I64d", &a[i] ); if ( !cnt || a[i] != color[cnt] ) { cnt ++; color[cnt] = a[i]; num[cnt] = 1; } else num[cnt] ++; if ( num[cnt] == k ) num[cnt] = 0, cnt --; } for ( int i = 1; i <= cnt; i ++ ) tot += num[i]; int h = 1, t = cnt; while ( h < t && color[h] == color[t] ) { if ( ( num[h] + num[t] ) % k == 0 ) h ++, t --; else { num[h] = ( num[h] + num[t] ) % k; num[t] = 0; break; } } ll ans = 0; if ( h < t ) { for ( int i = h; i <= t; i ++ ) ans += num[i]; ans *= ( m - 1 ); ans += tot; } else if ( h == t ) { if ( m * num[h] % k == 0 ) ans = 0; else { ans = tot + num[h] * ( m - 1 ); ans -= num[h] * m - num[h] * m % k; } } printf ( "%I64d", ans ); return 0; } /* 49 3 10 2 50 1 2 1 51 */
stl太强大了!!!这完全就是$set$模板题qwqwqwqwq。
发现行数很小,m=1时直接一遍扫,m=2时枚举第一行到第二行的断点,用前缀和直接计算,也是$O(n)$复杂度。
m=3时怎么做?在set中维护$pre[3][i]-pre[2][i]$,在枚举枚举1到2的断点时,在set中查找最优的2到3的断点,设此时只有1到2断点时答案为tmp,要使最终答案在$mod p$下最优,即尽量靠近$p-tmp-1$,在set中可以直接用lower_bound查找大于等于$p-tmp$的第一个位置,减一即为所求值的位置。还有一种情况,因为tmp和set中的值都mod了p,所以加起来不大于$2p$,直接查找最大值。两个值相比较更新答案。
#include<iostream> #include<cstdio> #include<set> #define ll long long using namespace std; set < ll > s; int n, m; ll pre[4][100005], a[4][100005], p, dp[4][100005], S; int main ( ) { freopen ( "candy.in", "r", stdin ); freopen ( "candy.out", "w", stdout ); scanf ( "%d%d%I64d", &n, &m, &p ); for ( int i = 1; i <= m; i ++ ) for ( int j = 1; j <= n; j ++ ) { scanf ( "%I64d", &a[i][j] ); S += a[i][j]; pre[i][j] = ( pre[i][j-1] + a[i][j] ) % p; } if ( m == 1 ) { printf ( "%I64d", pre[1][n] ); } else if ( m == 2 ) { ll ans = 0; for ( int i = 1; i <= n; i ++ ) ans = max ( ans, ( ( ( pre[1][i] + pre[2][n] ) % p - pre[2][i-1] ) % p + p ) % p ); printf ( "%I64d", ans ); } else if ( S < p ) { for ( int i = 1; i <= m; i ++ ) for ( int j = 1; j <= n; j ++ ) dp[i][j] = max ( dp[i-1][j]+a[i][j], dp[i][j-1]+a[i][j] ); printf ( "%I64d", dp[m][n] ); } else { ll ans = 0; for ( int i = n; i >= 1; i -- ) { ll tmp = ( ( ( pre[1][i] + pre[2][n] ) % p - pre[2][i-1] ) % p + p ) % p; ll pp = ( ( ( ( pre[3][n] - pre[3][i-1] ) % p + p - pre[2][n] ) % p + p ) % p + pre[2][i-1] ) % p; s.insert ( pp ); set < ll > :: iterator it, itt; it = s.lower_bound ( p - tmp ); if ( it != s.begin ( ) ) it --; itt = s.end ( ); if ( itt != s.begin ( ) ) itt --; ans = max ( ans, max ( ( tmp + *it ) % p, ( tmp + *itt ) % p ) ); } printf ( "%I64d", ans ); } return 0; }
又是一道无脑最小割...所有点拆成出点和入点,之间正常建边,出点连向起点,流量为wi-,入点连向终点,流量为wi+,最小割即可。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define inf 0x3f3f3f3f using namespace std; int n, m, ru[105], chu[105], s, t; int stot = 1, nex[1000005], tov[1000005], f[1000005], h[10005], hh[10005]; void add ( int u, int v, int ff ) { tov[++stot] = v; f[stot] = ff; nex[stot] = h[u]; h[u] = stot; tov[++stot] = u; f[stot] = 0; nex[stot] = h[v]; h[v] = stot; } queue < int > q; int dis[10005], vis[10005]; bool bfs ( ) { memset ( dis, 0, sizeof ( dis ) ); memset ( vis, 0, sizeof ( vis ) ); q.push ( s ); vis[s] = 1; while ( !q.empty ( ) ) { int u = q.front ( ); q.pop ( ); for ( int i = h[u]; i; i = nex[i] ) { int v = tov[i]; if ( !vis[v] && f[i] ) { dis[v] = dis[u] + 1; vis[v] = 1; q.push ( v ); } } } return vis[t]; } int dfs ( int u, int delta ) { if ( u == t ) return delta; int res = 0; for ( int i = hh[u]; i && delta; i = nex[i] ) { int v = tov[i]; if ( dis[v] == dis[u] + 1 && f[i] ) { int dd = dfs ( v, min ( delta, f[i] ) ); res += dd; f[i] -= dd; f[i^1] += dd; delta -= dd; hh[u] = i; } } return res; } int main ( ) { freopen ( "game.in", "r", stdin ); freopen ( "game.out", "w", stdout ); scanf ( "%d%d", &n, &m ); s = 0, t = n * 2 + 1; for ( int i = 1; i <= n; i ++ ) { int w; scanf ( "%d", &w ); add ( i + n, t, w ); } for ( int i = 1; i <= n; i ++ ) { int w; scanf ( "%d", &w ); add ( s, i, w ); } for ( int i = 1; i <= m; i ++ ) { int u, v; scanf ( "%d%d", &u, &v ); add ( u, v + n, inf ); } int ans = 0; while ( bfs ( ) ) { for ( int i = s; i <= t; i ++ ) hh[i] = h[i]; ans += dfs ( s, inf ); } printf ( "%d", ans ); return 0; }