2019 Multi-University Training Contest 1 1001 Blank

HDU 6578 Blank
题意: 给定1,N 的位置,每个位置可以填1,2,3,4其中一个,给m个区间[l,r] x ,限制[l,r]区间内只有x种不同的数。
题解: n非常小,只有100,可以直接用数组枚举上一个数出现的位置,每个位置暴力填就行了。直接 O ( n 4 ) O(n^4) O(n4)会T,。,必须要削常数。可以发现出现是什么数本身不重要,只和位置有关。然后最大的那个位置,一定是你要填的这个pos-1,所以dp空间可以优化一维,dp[i][j][k],代表排序后位置分别是i<j<k<pos-1,然后枚举的状态也是i<j<k<pos-1 ,对于限制条件,判断一下状态合不合法就行了。对于某个pos到了[l,r] x,r的位置,判断一下就行了,这个不影响复杂度。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<bitset>
#include<unordered_map>
#include<unordered_set>

using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> P;

#define VNAME(value) (#value)
#define bug printf("*********\n");
#define debug(x) cout<<"["<<VNAME(x)<<" = "<<(x)<<"]"<<endl;
#define mid (l+r)/2
#define chl 2*k+1
#define chr 2*k+2
#define lson l,mid,chl
#define rson mid+1,r,chr
#define pb push_back
#define mem(a, b) memset(a,b,sizeof(a));

const long long mod = 998244353;
const int maxn = 1e6 + 5;
const int INF = 0x7fffffff;
const LL inf = 0x3f3f3f3f;
const double eps = 1e-8;

void f() {
#ifndef ONLINE_JUDGE
    freopen("../data.in", "r", stdin);
#endif // ONLIN_JUDGE
}

LL dp[105][105][105][2];

struct node {
    int l, r, x;

    bool operator<(node &t) const {
        if (r == t.r)return l < t.l;
        return r < t.r;
    }
} dat[maxn];

int n, m;

void check(LL &x) {
    x %= mod;
}

int main() {
    f();
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= m; i++) {
            scanf("%d%d%d", &dat[i].l, &dat[i].r, &dat[i].x);
            dat[i].l += 3;
            dat[i].r += 3;
        }
        dp[0][1][2][1] = 1;
        sort(dat + 1, dat + m + 1);
        int l = 1, p = 0;
        for (int pos = 4; pos <= n + 3; pos++, p = !p) {
            for (int i = 0; i <= pos - 4; i++) {
                for (int j = i + 1; j <= pos - 3; j++) {
                    for (int k = j + 1; k <= pos - 2; ++k) {
                        int flag = 0, temp = l;
                        while (temp <= m && pos - 1 == dat[temp].r) {
                            if (dat[temp].x == 1 && dat[temp].l <= k) {
                                flag = 1;
                            }
                            if (dat[temp].x == 2 && (dat[temp].l <= j || dat[temp].l > k)) {
                                flag = 1;
                            }
                            if (dat[temp].x == 3 && (dat[temp].l <= i || dat[temp].l > j))flag = 1;
                            if (dat[temp].x == 4 && dat[temp].l > i)flag = 1;
                            temp++;
                        }
                        if (flag) {
                            dp[i][j][k][!p] = 0;
                            continue;
                        }
                        dp[j][k][pos - 1][p] += dp[i][j][k][!p];
                        check(dp[j][k][pos - 1][p]);
                        dp[i][k][pos - 1][p] += dp[i][j][k][!p];
                        check(dp[i][j][pos - 1][p]);
                        dp[i][j][pos - 1][p] += dp[i][j][k][!p];
                        check(dp[i][j][pos - 1][p]);
                        dp[i][j][k][p] += dp[i][j][k][!p];
                        check(dp[i][j][k][p]);
                        dp[i][j][k][!p] = 0;
                    }
                }
            }
            while (l <= m && dat[l].r == pos - 1)l++;
        }
        LL ans = 0;
        for (int i = 0; i <= n + 3; i++) {
            for (int j = i + 1; j <= n + 3; j++) {
                for (int k = j + 1; k <= n + 3; ++k) {
                    int flag = 0, temp = l;
                    while (temp <= m) {
                        if (dat[temp].x == 1 && dat[temp].l <= k) {
                            flag = 1;
                        }
                        if (dat[temp].x == 2 && (dat[temp].l <= j || dat[temp].l > k)) {
                            flag = 1;
                        }
                        if (dat[temp].x == 3 && (dat[temp].l <= i || dat[temp].l > j))flag = 1;
                        if (dat[temp].x == 4 && dat[temp].l > i)flag = 1;
                        temp++;
                    }
                    if (flag) {
                        dp[i][j][k][!p] = 0;
                        continue;
                    }
                    ans = (ans + dp[i][j][k][!p] % mod) % mod;
                    dp[i][j][k][!p] = 0;
                }
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}
/*
6
1 0
4
10 0
1048576
11 0
4194304
20 0
444595123
30 0
682155965
40 0
382013690
 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值