zoukankan      html  css  js  c++  java
  • [CQOI2018]解锁屏幕

    Description:

    使用过Android 手机的同学一定对手势解锁屏幕不陌生。Android 的解锁屏幕由3X3 个点组成,手指在屏幕上画一条线,将其中一些点连接起来,即可构成一个解锁图案。如下面三个例子所示

    题目描述:

    画线时还需要遵循一些规则:

    连接的点数不能少于4 个。也就是说只连接两个点或者三个点会提示错误。

    两个点之间的连线不能弯曲。

    每个点只能“使用”一次,不可重复。这里的“使用”是指手指划过一个点,该点变绿。

    两个点之间的连线不能“跨过”另一个点,除非那个点之前已经被“使用”过了。

    对于最后一条规则,参见下图的解释。左边两幅图违反了该规则; 而右边两幅图(分别为2->4-1-3-6 和6->5-4->1->9-2) 则没有违反规则,因为在“跨过”点时,点已经被“使用”过了。

    现在工程师希望改进解锁屏幕,增减点的数目,并移动点的位置,不再是一个九宫格形状,但保持上述画线的规则不变。请计算新的解锁屏幕上,一共有多少满足规则的画线方案。

    Hint:

    (n le 20)

    Solution:

    状压SB题,但是被细节坑了好多次??

    #include <bits/stdc++.h>
    #include <set>
    #include <stack>
    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #define ls p<<1 
    #define rs p<<1|1
    #define blt(i) __builtin_popcount(i)
    using namespace std;
    typedef long long ll;
    const int mod=1e8+7;
    inline int read() {
        char c=getchar(); int x=0,f=1;
        while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
        while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
        return x*f;
    }
    inline int chkmax(int &x,int y) {if(x<y) x=y;}
    inline int chkmin(int &x,int y) {if(x>y) x=y;}
    
    const int mxn=1e6+5; //数组开小,WA成狗
    int n,ans,x[mxn],y[mxn],dp[mxn][25];
    int f[55][55]; //一开始用map.....结果TLE成狗23333
    
    int check(int a,int b,int t) {
        int tp=f[a][b];
        if((tp&t)==tp) return 1;
        else return 0;
    }
    
    int main()
    {
        n=read();
        for(int i=1;i<=n;++i) 
            x[i]=read(),y[i]=read();
        for(int i=1;i<=n;++i) {
            for(int j=i+1;j<=n;++j) {
                for(int k=1;k<=n;++k) {
                    if(k==i||k==j) continue ;
                    if((y[i]-y[k])*(x[i]-x[j])==(x[i]-x[k])*(y[i]-y[j]))
                        if((x[k]-x[j])*(x[k]-x[i])<0||(y[k]-y[i])*(y[k]-y[j])<0) //注意还要考虑线段的多种情况 
                            f[i][j]|=(1<<(k-1)),f[j][i]=f[i][j];		
                }
            }
        }	
        for(int i=0;i<n;++i) dp[(1<<i)][i+1]=1;
        for(int i=1;i<(1<<n);++i) {
            for(int j=1;j<=n;++j) {
                if(i&(1<<(j-1)))
                for(int k=0;k<n;++k) 
                    if(!(i>>k&1)) 
                        if(check(j,k+1,i)) 
                            (dp[i|(1<<k)][k+1]+=dp[i][j])%=mod;
                
                if(blt(i)>3) ans=(ans+dp[i][j])%mod;
            }
        }
        printf("%d",ans);
        return 0;
    }
    
    
  • 相关阅读:
    一个提高N倍系统新能的编程点,却总是被普通开发们遗忘
    工作不到一年,做出了100k系统,老板给我升职加薪
    offer收割机也有方法论
    最长公共前缀
    罗马数字转整数
    回文数
    整数反转
    两数之和
    网页中Office和pdf相关文件导出
    搭建一个低配版的Mock Server
  • 原文地址:https://www.cnblogs.com/list1/p/10544259.html
Copyright © 2011-2022 走看看