[gym102832J]Abstract Painting

考虑每一个圆即对应于区间$[x_{i}-r_{i},x_{i}+r_{i}]$,可以看作对于每一个区间,要求所有右端点严格比其小的区间不严格包含左端点

用$f_{i}$表示仅考虑右端点不超过$i$的区间的方案数,分为两类:

1.第$i$个节点不作为右端点,即$f_{i-1}$;

2.第$i$个节点作为右端点,也就是说可以产生$[i-2r,i]$这些区间($1\le r\le 5$),且这些区间是可以同时产生的,只需要记录是否存在一个区间严格包含$i-2r$即可(包含即不合法)

(特别的,对于$i>n$时,需要保证$i-r\le n$)

状压即可,时间复杂度为$o(2^{9}n)$(关于以$i$为右端点的区间可以$o(5)$去计算,只关心于最大的区间以及比他小且可以任意确定的区间)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 1005 
 4 #define mod 1000000007
 5 int n,m,x,r,ans,v[N][11],f[N][N];
 6 int main(){
 7     scanf("%d%d",&n,&m);
 8     for(int i=1;i<=m;i++){
 9         scanf("%d%d",&x,&r);
10         v[x+r][r]=1;
11     }
12     f[0][0]=1;
13     for(int i=1;i<=n;i++)
14         for(int j=0;j<(1<<9);j++){
15             bool flag=0;
16             for(int k=1;k<=5;k++)
17                 if ((v[i][k])&&(j&(1<<2*k-2))){
18                     flag=1;
19                     break;
20                 }
21             if (flag)continue;
22             int mx=0,tot=0;
23             for(int k=1;k<=5;k++)
24                 if (v[i][k])mx=k;
25             for(int k=1;k<=mx;k++)
26                 if ((!v[i][k])&&((j&(1<<2*k-2))==0))tot++;
27             int jj=((j<<1)&((1<<9)-1));
28             if (!mx){
29                 f[i][jj]=(f[i][jj]+f[i-1][j])%mod;
30                 mx=1;
31             }
32             for(int k=mx;k<=min(i/2,5);k++)
33                 if ((j&(1<<2*k-2))==0){
34                     f[i][jj|((1<<2*k-1)-1)]=(f[i][jj|((1<<2*k-1)-1)]+(1LL<<tot)*f[i-1][j])%mod;
35                     if (!v[i][k])tot++;
36                 }
37         }
38     for(int i=0;i<(1<<9);i++)ans=(ans+f[n][i])%mod;
39     printf("%d",ans);
40 }
View Code

 

posted @ 2021-02-01 19:04  PYWBKTDA  阅读(120)  评论(0编辑  收藏  举报