[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)$去计算,只关心于最大的区间以及比他小且可以任意确定的区间)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }