CCPC2020长春 J. Abstract Painting(状压dp)

   日期:2020-11-10     浏览:124    评论:0    
核心提示:J. Abstract Painting(状压dp)题意给定n,在x轴[0,n]范围内画半径不超过5的圆,圆心在x轴上,要求任意两个圆不相交(可以相切),且已有固定的k个圆,求满足条件的画法方案数。分析很明显从dp的角度思考,一开始考虑区间dp,但是总状态数O(n2)O(n^2)O(n2) ,转移O(n)O(n)O(n),总复杂度O(n3)O(n^3)O(n3),超时。于是从线性dp的角度考虑,发现因为圆的半径小于等于5,因此某一点的情况只对从这一点往后10个点有后效性,也就是说可以用状态压缩的

J. Abstract Painting(状压dp)

题意

给定n,在x轴[0,n]范围内画半径不超过5的圆,圆心在x轴上,要求任意两个圆不相交(可以相切),且已有固定的k个圆,求满足条件的画法方案数。

分析

很明显从dp的角度思考,一开始考虑区间dp,但是总状态数 O ( n 2 ) O(n^2) O(n2) ,转移 O ( n ) O(n) O(n),总复杂度 O ( n 3 ) O(n^3) O(n3),超时。

于是从线性dp的角度考虑,发现因为圆的半径小于等于5,因此某一点的情况只对从这一点往后10个点有后效性,也就是说可以用状态压缩的方法记录前10个点是否在某个圆内 ( 2 10 ) (2^{10}) (210),同时枚举所有以某点为右界的圆的方案数( 2 5 2^5 25)进行转移。状态数 O ( 2 10 ⋅ n ) O(2^{10}·n) O(210n),转移复杂度 O ( 2 5 ) O(2^5) O(25)。对于已经存在的圆,转移时要检查转移后的方案是否包含了这个圆,如果不包含则不进行转移。

代码

#include <bits/stdc++.h>
#define debug(x) cerr << #x << " = " << x << ' '
#define debugl(x) cerr << #x << " = " << x << '\n'

using namespace std;
typedef long long ll;

const int N = 1e3 + 5, M = 1200, MOD = 1e9 + 7, MK = 1023;

int n, k;

ll dp[N][M];

int pos[40], mask[40];

vector<int> fix[N];

int main() { 
    cin >> n >> k;
    for (int i = 1; i <= k; i++) { 
        int c, r; scanf("%d %d", &c, &r);
        c++;
        fix[c + r].push_back(r * 2);
    }
    memset(mask, -1, sizeof(mask));
    for (int i = 1; i <= 31; i++) { 
        int tmp = 0;
        for (int j = 4; j >= 0; j--) { 
            tmp = (tmp * 2 + ((i >> j) & 1)) * 2;
            if (mask[i] == -1 && ((i >> j) & 1)) mask[i] = (1 << (j * 2 + 1)) - 1;
        }
        pos[i] = tmp;
    }
    dp[0][MK] = 1;
    for (int i = 0; i <= n; i++) { 
        for (int j = 0; j <= MK; j++) { 
            if (fix[i + 1].size() == 0) { 
                dp[i + 1][(j << 1) & MK] += dp[i][j];
                dp[i + 1][(j << 1) & MK] %= MOD;
            }
            for (int k = 1; k <= 31; k++) { 
                bool cont = 0;
                for (int to : fix[i + 1]) { 
                    if (!((pos[k] >> (to - 1)) & 1)) cont = 1;
                    if (cont) break;
                }
                if (cont || (j & pos[k]) != 0) continue;
                dp[i + 1][(((j | mask[k]) << 1)) & MK] += dp[i][j];
                dp[i + 1][(((j | mask[k]) << 1)) & MK] %= MOD;
            }
        }
    }
    ll ans = 0;
    for (int i = 0; i <= MK; i++) { 
        ans += dp[n + 1][i];
        ans %= MOD;
    }
    cout << ans;
    return 0;
}
 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服