• 【arc062e】Building Cubes with AtCoDeer


    Description

    STL有n块瓷砖,编号从1到n,并且将这个编号写在瓷砖的正中央;

    瓷砖的四个角上分别有四种颜色(可能相等可能不相等),并且用Ci,0,Ci,1,Ci,2,Ci,3分别表示左上、右上、右下、左下的颜色。颜色有1000种,编号从0到999。

    现在STL想知道,从这n块瓷砖中选出不同的6块,能围成多少本质不同的合法的立方体。

    一个立方体被称为合法的,当且仅当瓷砖有编号的一侧在外面,并且立方体的每个顶点处的三个颜色相同。

    注意,由于瓷砖的中间是写着编号的,因此将一个瓷砖旋转90度之后,这个瓷砖会发生变化,也就是说一块瓷砖可以被用作四个方向(哪怕旋转后四个角的颜色对应相等)。

    两个立方体被称作是本质相同的,当且仅当存在在空间中旋转一个立方体的方式,使其和第二个立方体一模一样(包括每面瓷砖上编号的方向)。


    Solution

    n最大为400,显然可以暴力解决。

    我们可以发现,当一个立方体中,只要确定了任意两个相对的面,就可唯一确定整个立方体。

    因此我们枚举相对两面编号及编号方向,用map储存瓷砖,计算方案即可。

    ps:由于正方形可旋转,因此存入map时,要将旋转4次的结果都存入map中。

    Code

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<map>
     5 using namespace std;
     6 #define hash func
     7 typedef long long ll;
     8 int n,c[410][4];
     9 ll ans=0,h[410];
    10 map<ll,int>mp;
    11 ll hash(ll a,ll b,ll c,ll d){
    12     return a<<30|b<<20|c<<10|d;
    13 }
    14 void add(ll x,int k){
    15     for(int i=4;i;x=x>>10|(x&1023)<<30,i--)
    16         mp[x]+=k;
    17     return;
    18 }
    19 int main(){
    20     mp.clear();
    21     scanf("%d",&n);
    22     for(int i=1;i<=n;i++){
    23         scanf("%d%d%d%d",c[i]+0,c[i]+1,c[i]+2,c[i]+3);
    24         h[i]=hash(c[i][0],c[i][1],c[i][2],c[i][3]);
    25         add(h[i],1);
    26     }
    27     for(int i=1;i<n-4;i++){
    28         add(h[i],-1);
    29         for(int j=i+1;j<=n;j++){
    30             add(h[j],-1);
    31             for(int k=0;k<4;k++){
    32                 ll a[4];
    33                 a[0]=hash(c[i][3],c[i][2],c[j][(k+1)%4],c[j][k]);
    34                 a[1]=hash(c[i][2],c[i][1],c[j][(k+2)%4],c[j][(k+1)%4]);
    35                 a[2]=hash(c[i][1],c[i][0],c[j][(k+3)%4],c[j][(k+2)%4]);
    36                 a[3]=hash(c[i][0],c[i][3],c[j][k],c[j][(k+3)%4]);
    37                 if(mp[a[0]]==0||mp[a[1]]==0||mp[a[2]]==0||mp[a[3]]==0)
    38                     continue;
    39                 ll res=1;
    40                 for(int l=0;l<4;l++){
    41                     res*=mp[a[l]];
    42                     add(a[l],-1);
    43                 }
    44                 ans+=res;
    45                 for(int l=0;l<4;l++)
    46                     add(a[l],1);
    47             }
    48             add(h[j],1);
    49         }
    50     }
    51     printf("%lld\n",ans);
    52     return 0;
    53 }
  • 相关阅读:
    初学者易上手的SSH-spring 01控制反转(IOC)
    初学者易上手的SSH-hibernate04 一对一 一对多 多对多
    初学者易上手的SSH-hibernate03 三大状态与缓存
    初学者易上手的SSH-hibernate02 三种查询方式
    初学者易上手的SSH-hibernate01环境搭建
    Maven-环境搭建以及建立Maven项目
    初学者易上手的SSH-struts2 05拦截器与自定义拦截器
    初学者易上手的SSH-struts2 04值栈与ognl表达式
    screen常用操作总结
    word2016教程:使用密码保持修订
  • 原文地址:https://www.cnblogs.com/gzez181027/p/arc062e.html
Copyright © 2020-2023  润新知