【LOJ】#3051. 「十二省聯考 2019」皮配

LOJ#3051. 「十二省聯考 2019」皮配

當時我在考場上以爲這題很不可作。。。c++

固然,出了考場後再作,我仍是沒發現學校和城市是能夠分開的,致使我仍是不會數組

事實上,若一個城市投靠了某個陣營,學校能夠任意選擇派系,可是反過來看,學校選擇了派系,也不影響城市投靠什麼陣營,而這二者共同固定了一個學校選擇的導師,因此對於k = 0的狀況spa

咱們設兩個dp,\(g[i][j]\)表示考慮了前i個城市,去藍陣營的人數爲j,\(h[i][j]\)表示考慮了前i個城市,去鴨派系的人數爲j,最後只須要把合法的分別乘起來就好code

對於\(k!=0\)的狀況,沒有限制的城市,和沒有限制的學校,均可以按照k = 0的方案去作ci

然而這些限制給的是什麼呢,能夠認爲是選了一些藍陣營的城市,將致使咱們必須選鴨派系或者必須選R派系,選了紅陣營亦然。這個時候二者就有關係了,因此設\(f[i][j][k]\)是考慮了前i個有限制的城市,選了藍陣營的城市總人數爲\(j\)在,在有限制的學校中選了鴨派系的人數是\(k\)get

滾動數組就能夠開的下了it

而後答案合併的時候是會選擇g和h一段連續的區間和\(f[i][j][k]\)合併,計算上下界查區間和便可class

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define eps 1e-10
#define ba 47
//#define ivorysi
#define MAXN 50010
#define MAXM 200005
using namespace std;
typedef long long int64;
typedef unsigned int u32;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;T f = 1;char c = getchar();
    while(c < '0' || c > '9') {
    if(c == '-') f = -1;
    c = getchar();
    }
    while(c >= '0' && c <= '9') {
    res = res * 10 +c - '0';
    c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) {
    out(x / 10);
    }
    putchar('0' + x % 10);
}
const int MOD = 998244353;
int n,c,k,C0,C1,D0,D1;
vector<int> city[1005];
int f[2505][305],g[2505],h[2505],tmp[305];
int b[1005],s[1005],p[1005],all;
bool lim[1005],dl[1005];
int inc(int a,int b) {
    return a + b >= MOD ? a + b - MOD : a + b;
}
int mul(int a,int b) {
    return 1LL * a * b % MOD;
}
void update(int &x,int y) {
    x = inc(x,y);
}
void Init() {
    read(n);read(c);
    read(C0);read(C1);read(D0);read(D1);
    for(int i = 1 ; i <= c ; ++i) city[i].clear();
    memset(lim,0,sizeof(lim));memset(dl,0,sizeof(dl));
    all = 0;
    for(int i = 1 ; i <= n ; ++i) {
    read(b[i]);read(s[i]);all += s[i];
    city[b[i]].pb(i);
    }
    read(k);
    int a;
    for(int i = 1 ; i <= k ; ++i) {
    read(a);read(p[a]);
    dl[a] = 1;lim[b[a]] = 1;
    }
}
void Solve() {
    memset(g,0,sizeof(g));
    g[0] = 1;
    for(int i = 1 ; i <= c ; ++i) {
    if(!lim[i] && city[i].size() > 0) {
        int sum = 0;
        for(auto t : city[i]) {
        sum += s[t];
        }
        for(int j = C0; j >= sum ; --j) {
        update(g[j],g[j - sum]);
        }
    }
    }
    memset(h,0,sizeof(h));
    h[0] = 1;
    for(int i = 1 ; i <= n ; ++i) {
    if(!dl[i]) {
        for(int j = D0 ; j >= s[i] ; --j) {
        update(h[j],h[j - s[i]]);
        }
    }
    }
    memset(f,0,sizeof(f));
    f[0][0] = 1;
    int tot = 0,nl = 0;
    for(int i = 1 ; i <= c ; ++i) {
    if(lim[i]) {
        int sum = 0,s1 = 0;
        for(auto t : city[i]) {
        sum += s[t];
        if(dl[t]) s1 += s[t];
        }
        tot = tot + sum;tot = min(tot,C0);
        nl = nl + s1;nl = min(nl,D0);
        for(int j = tot; j >= 0 ; --j) {
        for(int r = 0 ; r <= nl ; ++r) tmp[r] = f[j][r];
        for(auto t : city[i]) {
            if(dl[t]) {
            if(p[t] >= 2) {
                if(p[t] == 2) continue;
                else {
                for(int r = nl ; r >= 0 ; --r) {
                    if(r >= s[t]) tmp[r] = tmp[r - s[t]];
                    else tmp[r] = 0;
                }
                }
            }
            else {
                for(int r = nl ; r >= s[t] ; --r) update(tmp[r],tmp[r - s[t]]);
            }
            }
        }
        for(int r = 0 ; r <= nl ; ++r) f[j][r] = tmp[r];
        if(j >= sum) {
            for(int r = 0 ; r <= nl ; ++r) tmp[r] = f[j - sum][r];
            for(auto t : city[i]) {
            if(dl[t]) {
                if(p[t] < 2) {
                if(p[t] == 0) continue;
                else {
                    for(int r = nl ; r >= 0 ; --r) {
                    if(r >= s[t]) tmp[r] = tmp[r - s[t]];
                    else tmp[r] = 0;
                    }
                }
                }
                else {
                for(int r = nl ; r >= s[t] ; --r) update(tmp[r],tmp[r - s[t]]);
                }
            }
            }
            for(int r = 0 ; r <= nl ; ++r) update(f[j][r],tmp[r]);
        }
        
        }
    }
    }
    for(int i = 1 ; i <= C0 ; ++i) update(g[i],g[i - 1]);
    for(int i = 1 ; i <= D0 ; ++i) update(h[i],h[i - 1]);
    int ans = 0;
    for(int i = 0 ; i <= C0 ; ++i) {
    for(int j = 0 ; j <= 300 ; ++j) {
        int t0 = 0,t1 = 0;
        int u = C0 - i,d = all - C1 - i;
        if(d <= u) {
        t0 = g[u];
        if(d > 0) update(t0,MOD - g[d - 1]);
        }
        u = D0 - j,d = all - D1 - j;
        if(d <= u) {
        t1 = h[u];
        if(d > 0) update(t1,MOD - h[d - 1]);
        }
        update(ans,mul(f[i][j],mul(t0,t1)));
    }
    }
    out(ans);enter;
    cerr << ans;
}
int main(){
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    int T;
    read(T);
    for(int i = 1 ; i <= T ; ++i) {
    Init();
    Solve();
    }
}
相關文章
相關標籤/搜索