bzoj5299: [Cqoi2018]解锁屏幕
9.2s时间感人,没判好边界WA*2
这题看到n这么小,当然考虑一下状压
令f[i][zt]表示到达第i个点,zt就是取了和没取的状态咯
弄个li[i][j]表示假如i要->j,那么需要哪些点已经取了,这个根据题意就是斜率一样并且在两点之间
枚举状态,枚举出发和到达点,判断是否可行即可。
O(n^2*2^n),但是有很多到达不了的所以堪堪可过吧
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; const LL mod=100000007; struct node { int x,y; }a[30]; int li[30][30]; LL f[21][1100000]; int main() { freopen("data.in","r",stdin); freopen("1.out","w",stdout); int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) { int zz=0; for(int k=1;k<=n;k++) if(k!=i&&k!=j) { if( ((a[i].y-a[k].y)*(a[j].x-a[k].x)==(a[j].y-a[k].y)*(a[i].x-a[k].x)) && ( ( (a[i].x<=a[k].x)&&(a[k].x<=a[j].x) && (a[i].y<=a[k].y)&&(a[k].y<=a[j].y) ) || ( (a[i].x>=a[k].x)&&(a[k].x>=a[j].x) && (a[i].y>=a[k].y)&&(a[k].y>=a[j].y) ) || ( (a[i].x>=a[k].x)&&(a[k].x>=a[j].x) && (a[i].y<=a[k].y)&&(a[k].y<=a[j].y) ) || ( (a[i].x<=a[k].x)&&(a[k].x<=a[j].x) && (a[i].y>=a[k].y)&&(a[k].y>=a[j].y) ) ) )zz|=(1<<(k-1)); } li[i][j]=li[j][i]=zz; li[i][j]|=(1<<(i-1)); li[j][i]|=(1<<(j-1)); } int u=(1<<n)-1; memset(f,0,sizeof(f)); for(int i=1;i<=n;i++)f[i][(1<<(i-1))]=1; for(int zt=1;zt<=u;zt++) { for(int i=1;i<=n;i++) { if((zt&(1<<(i-1)))>0&&f[i][zt]!=0) { for(int j=1;j<=n;j++) { if((zt&(1<<(j-1)))>0)continue; if((zt&li[i][j])==li[i][j]) f[j][zt|(1<<(j-1))]=(f[j][zt|(1<<(j-1))]+f[i][zt])%mod; } } } } LL ans=0; for(int zt=1;zt<=u;zt++) { int o=0; for(int i=1;i<=n;i++) if((zt&(1<<(i-1)))>0)o++; if(o>=4) { for(int i=1;i<=n;i++) ans=(ans+f[i][zt])%mod; } } printf("%lld\n",ans); return 0; }
pain and happy in the cruel world.