【8.17校内测试】【模拟】【set】【网络流】

为什么每次想的最久的题得的分数最低!!!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;
}

 

posted @ 2018-08-17 17:05  Wans_ovo  阅读(221)  评论(2)    收藏  举报