• [CQOI2018] 解锁屏幕


    Description

    给定安卓屏幕上 (n;(nleq 20)) 个点,要求设计解锁图案,连接规则遵循安卓屏幕解锁连接规则,问有多少种解锁图案?

    Solution

    题外话:今天刷鞋了好爽啊哈哈哈培训有鞋穿了啊哈哈哈

    数据范围一眼状压

    联想到愤怒的小鸟那题,容易想到定义 (mp[i][j]) 表示在连接 (i,j) 的同时还能连接上哪些中间的点,然后转移的时候或一下就行了。

    但是这样会有 (bug),比如说三个点 ((0,0),(1,1),(2,2)) 实际上从1直接连到3和先连到2再连到3是完全一样的方案,但是统计的时候会统计两遍。

    考虑改变 (mp) 数组的定义,(mp[i][j]) 变为要连接 (i,j) 两个点,中间会经过多少点,那么转移的时候我们钦定中间要经过的这些点都必须在之前被连上过,这样转移就不会记重了。

    ps:这题据说考试的时候不开O2,尝试卡了一下常,发现 register 真好用,顺便发现 inline 没啥用?

    Code

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #define N 21
    #define in inline
    #define re register
    const int mod=100000007;
    #define min(A,B) ((A)<(B)?(A):(B))
    #define max(A,B) ((A)>(B)?(A):(B))
    #define swap(A,B) ((A)^=(B)^=(A)^=(B))
    
    int n;
    int ok[N][N];
    int mp[N][N];
    int x[N],y[N];
    int cnt[1<<20];
    int f[N][1<<20];
    
    int getint(){
        int x=0,f=0;char ch=getchar();
        while(!isdigit(ch)) f|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        return f?-x:x;
    }
    
    int M(int &x){
        while(x>=mod) x-=mod;
        while(x<0) x+=mod;
    }
    
    signed main(){
        n=getint();
        for(re int i=1;i<=n;i++)
            x[i]=getint(),y[i]=getint();
        int maxn=1<<n;
        for(re int i=0;i<maxn;i++)
            cnt[i]=cnt[i>>1]+(i&1);
        for(re int i=1;i<=n;i++){
            for(re int j=1;j<=n;j++){
                if(i==j) continue;
               for(re int k=1;k<=n;k++){
                    if(k==i or k==j) continue;
                    if((y[j]-y[i])*(x[j]-x[k])==(y[j]-y[k])*(x[j]-x[i])){
                        if(x[k]>max(x[i],x[j]) or x[k]<min(x[i],x[j]) or y[k]>max(y[i],y[j]) or y[k]<min(y[i],y[j]))
                            continue;
                        mp[i][j]|=1<<k-1;
                    }
                }
            }
        }
        for(re int i=1;i<=n;i++)
            f[i][1<<i-1]=1;
        for(re int i=0;i<maxn;i++){
            for(re int j=1;j<=n;j++){
                if((i&(1<<j-1))==0) continue;
                if(!f[j][i]) continue;
                for(re int k=1;k<=n;k++){
                    if(i&(1<<k-1)) continue;
                    if((mp[j][k]&i)!=mp[j][k]) continue;
                    M(f[k][i|(1<<k-1)]+=f[j][i]);
                    //printf("i=%d,j=%d,k=%d,i|=%d,f=%d,f=%d
    ",i,j,k,i|mp[j][k],f[j][i],f[k][i|mp[j][k]]);
                }
            }
        } 
        int ans=0;
        for(re int i=0;i<maxn;i++){
            if(cnt[i]>3){
                for(re int j=1;j<=n;j++){
                    if(i&(1<<j-1))
                        M(ans+=f[j][i]);
                }
            }
        }
        printf("%d
    ",ans);/*
        for(int i=0;i<maxn;i++){
            if(cnt[i]<=3) continue;
            printf("
    i=%d
    ",i);
            for(int j=1;j<=n;j++)
                printf("j=%d,f=%d
    ",j,f[j][i]);
        }*/
        return 0;
    }
    
  • 相关阅读:
    第四章 网络层协议介绍
    第三章 交换机基本原理与配置
    网络服务综合性测试
    双向秘钥对验证
    DNS分离解析与构建智能DNS服务器
    NFS共享服务
    部署YUM仓库服务
    PXE高效能批量网络装机
    DNS综合实验
    构建DNS主 从服务器
  • 原文地址:https://www.cnblogs.com/YoungNeal/p/9383856.html
Copyright © 2020-2023  润新知