算是我比较擅长的类型,自己想想就会了。普通小状压,状态傻子都能想出来。一开始裸的枚举T了,30.后来与处理之后跑的飞起,就是不对,还是30分。后来看讨论版。。。mod竟然是1e8+7!!!这不有毒吗。。。
题干:
题目背景 使用过Android 手机的同学一定对手势解锁屏幕不陌生。Android 的解锁屏幕由3X3 个点组成,手指在屏幕上画一条线,将其中一些点连接起来,即可构成一个解锁图案。如下面三个例子所示: 题目描述 画线时还需要遵循一些规则: 连接的点数不能少于4 个。也就是说只连接两个点或者三个点会提示错误。 两个点之间的连线不能弯曲。 每个点只能“使用”一次,不可重复。这里的“使用”是指手指划过一个点,该点变绿。 两个点之间的连线不能“跨过”另一个点,除非那个点之前已经被“使用”过了。 对于最后一条规则,参见下图的解释。左边两幅图违反了该规则; 而右边两幅图(分别为2->4-1-3-6 和6->5-4->1->9-2) 则没有违反规则,因为在“跨过”点时,点已经被“使用”过了。 现在工程师希望改进解锁屏幕,增减点的数目,并移动点的位置,不再是一个九宫格形状,但保持上述画线的规则不变。请计算新的解锁屏幕上,一共有多少满足规则的画线方案。 输入输出格式 输入格式: 输入文件第一行,为一个整数n,表示点的数目。 接下来n 行,每行两个空格分开的整数xix_ixi 和yiy_iyi,表示每个点的坐标。 输出格式: 输出文件共一行,为题目所求方案数除以100000007 的余数。
30
#include<iostream> #include<cstdio> #include<cmath> #include<ctime> #include<queue> #include<algorithm> #include<cstring> using namespace std; #define duke(i,a,n) for(register int i = a;i <= n;++i) #define lv(i,a,n) for(register int i = a;i >= n;--i) #define clean(a) memset(a,0,sizeof(a)) const int INF = 1 << 30; typedef long long ll; typedef double db; template <class T> void read(T &x) { char c; bool op = 0; while(c = getchar(), c < '0' || c > '9') if(c == '-') op = 1; x = c - '0'; while(c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; if(op) x = -x; } template <class T> void write(T x) { if(x < 0) putchar('-'), x = -x; if(x >= 10) write(x / 10); putchar('0' + x % 10); } const int mod = 1e9 + 7; const int N = 21; int dp[1 << N][N]; int x[N],y[N],n,ans; /*void dfs(int now,int u,int len)//zhuangtai.xianzaidedian,changdu { if(dp[now][u]) return dp[now][u]; for(int i = 1;i <= n;i++) { if(now & (1 << (i - 1)) == 0) { int ok = 0; duke(j,1,n) { if(now & (1 << (i - 1)) == 0) { if(check(u,j,i) == false) { ok = 1; break; } } } if(ok == 0) { dfs(now | (1 << (i - 1)),i,len + 1); dp[now][u] += dp[now | (1 << (i - 1))] } } } }*/ bool check(int a,int b,int c) { /*if(a == 1 && c == 3 && b == 2) printf("%d %d %d ",a,b,c);*/ if((y[b] - y[a]) * (x[c] - x[b]) != (y[c] - y[b]) * (x[b] - x[a])) return true; if(x[a] > x[b] && x[c] > x[b]) return true; if(x[a] < x[b] && x[c] < x[b]) return true; if(y[a] > y[b] && y[c] > y[b]) return true; if(y[a] < y[b] && y[c] < y[b]) return true; return false; } void p(int now) { duke(i,1,n) { if((now & (1 << (i - 1))) != 0) printf("1"); else printf("0"); } } int main() { read(n); duke(i,1,n) read(x[i]),read(y[i]); duke(i,0,n - 1) { dp[1 << i][i + 1] = 1; } for(int now = 1;now <= (1 << n) - 1;now++) { duke(i,1,n) { if((now & (1 << (i - 1))) != 0) { duke(j,1,n) { if((now & (1 << (j - 1))) != 0 && i != j) { int ok = 0; duke(k,1,n) { if((now & (1 << (k - 1))) == 0) if(check(i,k,j) == false) { ok = 1;//cout<<i<<" "<<j<<" "<<k<<endl; break; } } if(ok == 0) { dp[now][i] += dp[now - (1 << (i - 1))][j]; // p(now),printf(" ");cout<<i<<" "<<j;printf(" ");p(now - (1 << (i - 1))); // puts(""); dp[now][i] %= mod; } } } } } int tot = 0; duke(i,0,n - 1) { if((now & (1 << i)) != 0) tot++; } if(tot >= 4) { duke(i,1,n) { if((now & (1 << (i - 1))) != 0) ans += dp[now][i],ans %= mod; } } } // ans += 1; // ans /= 2; /*duke(i,0,(1 << n) - 1) { duke(j,1,n) if((i & (1 << (j - 1))) != 0) p(i),printf(" "),cout<<dp[i][j]<<endl; }*/ printf("%d ",ans); return 0; }
AC代码:
// luogu-judger-enable-o2 #include<iostream> #include<cstdio> #include<cmath> #include<ctime> #include<queue> #include<algorithm> #include<cstring> using namespace std; #define duke(i,a,n) for(register int i = a;i <= n;++i) #define lv(i,a,n) for(register int i = a;i >= n;--i) #define clean(a) memset(a,0,sizeof(a)) const int INF = 1 << 30; typedef long long ll; typedef double db; template <class T> void read(T &x) { char c; bool op = 0; while(c = getchar(), c < '0' || c > '9') if(c == '-') op = 1; x = c - '0'; while(c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; if(op) x = -x; } template <class T> void write(T x) { if(x < 0) putchar('-'), x = -x; if(x >= 10) write(x / 10); putchar('0' + x % 10); } const int mod = 1e8 + 7; const int N = 21; int dp[1 << N][N]; int x[N],y[N],n,ans; bool check(int a,int b,int c) { /*if(a == 1 && c == 3 && b == 2) printf("%d %d %d ",a,b,c);*/ if((y[b] - y[a]) * (x[c] - x[b]) != (y[c] - y[b]) * (x[b] - x[a])) return true; if(x[a] > x[b] && x[c] > x[b]) return true; if(x[a] < x[b] && x[c] < x[b]) return true; if(y[a] > y[b] && y[c] > y[b]) return true; if(y[a] < y[b] && y[c] < y[b]) return true; return false; } void p(int now) { duke(i,1,n) { if((now & (1 << (i - 1))) != 0) printf("1"); else printf("0"); } } vector <int> mp[N][N]; void init(int x,int y) { for(int i = 1;i <= n;i++) { if(check(x,i,y) == false) { mp[x][y].push_back(i); } } } int main() { read(n); duke(i,1,n) read(x[i]),read(y[i]); duke(i,0,n - 1) { dp[1 << i][i + 1] = 1; } duke(i,1,n) duke(j,1,n) init(i,j); for(int now = 1;now <= (1 << n) - 1;now++) { duke(i,1,n) { if((now & (1 << (i - 1))) != 0) { duke(j,1,n) { if((now & (1 << (j - 1))) != 0 && i != j) { int ok = 0; duke(f,0,(int)mp[i][j].size() - 1) { int k = mp[i][j][f]; if((now & (1 << (k - 1))) == 0) { ok = 1;//cout<<i<<" "<<j<<" "<<k<<endl; break; } } if(ok == 0) { dp[now][i] += dp[now - (1 << (i - 1))][j]; // p(now),printf(" ");cout<<i<<" "<<j;printf(" ");p(now - (1 << (i - 1))); // puts(""); dp[now][i] %= mod; } } } } } int tot = 0; duke(i,0,n - 1) { if((now & (1 << i)) != 0) tot++; } if(tot >= 4) { duke(i,1,n) { if((now & (1 << (i - 1))) != 0) ans += dp[now][i],ans %= mod; } } } // ans += 1; // ans /= 2; /*duke(i,0,(1 << n) - 1) { duke(j,1,n) if((i & (1 << (j - 1))) != 0) p(i),printf(" "),cout<<dp[i][j]<<endl; }*/ printf("%d ",ans); return 0; }
代码: