解题报告:HDU_6123 Destroy the cube (容斥+三元环计数)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_32570675/article/details/77723424

题目链接


题意及官方题解:



记录一下自己的做法:

首先如果可以直接跑全部的黑色位置,那就很好写,但是肯定会超时,所以一定要用对称性优化。

如果n为偶数,可以完美拆成八个完全一样的小正方体的子问题,很好写

如果n为奇数,问题就变得复杂而且要考虑各种细节。。

先不考虑最中间的面,解决八个小正方体的子问题

把中间面的所有黑色位置建图跑三元环

然后发现会有重复减掉的部分,加上这个部分

官方的数据有点弱,之前一些细节没有处理好的代码也能过


又丑又长代码:

#include<bits/stdc++.h>

#define LL long long
#define pii pair< int , int >
#define fi first
#define se second
const int N = 6e4+5;
using namespace std;

int num[2][3][2][N],n,nn,all[2];
map< unsigned , int > S[2];
vector<int>G[2][N],pos;
vector< pii >A;

bool has[N];

inline unsigned oper(unsigned a,unsigned b){return (a<<16) | b ;}
inline bool check(int a,int b,int k) {return  S[k].find(oper(a,b))!= S[k].end();}

inline void add(int a,int b,int k){
   if( ++S[k][oper(a,b)]==1 )G[k][a].emplace_back(b),++all[k];
   if(a!=b&&++S[k][oper(b,a)]==1)G[k][b].emplace_back(a),++all[k];
   ++num[k][0][0][a];++num[k][0][1][b];
   ++num[k][1][0][a];++num[k][1][1][b];
   ++num[k][2][0][b];++num[k][2][1][a];
}

inline int add(){
   int res = 0;
   for(int i=0;i<A.size();i++){
      pii& t = A[i];
      if(has[t.se]||has[t.fi])res += (t.fi==t.se?12:24);
   }return res;
}

inline int get(int a,int b,int c){
   int mi = min(a,min(b,c));
   int mx = max(a,max(b,c));
   int mm = a+b+c-mi-mx;
   int res = 3 - (mi==mm) - (mm==mx);
   if(res==3)return 6;
   return res==1?1:3;
}

inline int read()
{
    int x=0,f=1; char ch=getchar();
    while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}

inline LL work(int k){
   LL x = k?1:8 , ans = 0;
   int l = k?n:nn , m = sqrt(all[k]+0.5) ;
   for(int i=1;i<=l;i++){
      ans += x*num[k][0][0][i]*num[k][1][0][i];
      ans += x*num[k][0][1][i]*num[k][2][0][i];
      ans += x*num[k][1][1][i]*num[k][2][1][i];
   }pos.clear();
   for(int i=1,a,b;i<=l;++i)
   if(G[k][i].size()>m)pos.emplace_back(i);
   else for(int j=0;j<G[k][i].size();j++)if(G[k][a=G[k][i][j]].size()>m||a>=i)
         for(int q=j;q<G[k][i].size();q++)if((G[k][b=G[k][i][q]].size()>m||b>=i)&&check(a,b,k))
            ans-=x*get(i,b,a);
   for(int i=0;i<pos.size();i++)for(int j=i;j<pos.size();j++)if(check(pos[i],pos[j],k))
      for(int q=j;q<pos.size();q++)if(check(pos[j],pos[q],k)&&check(pos[i],pos[q],k))
         ans -= x*get(pos[i],pos[j],pos[q]);
   return ans-x*3*all[k]*l;
}

int main()
{
   int m,T=read();
   while(T--){S[0].clear();S[1].clear();A.clear();
      n=read();m=read();nn = n>>1;
      memset(num,0,sizeof(num));all[0] = all[1] = 0;
      for(int i=1;i<=n;i++)G[0][i].clear(),G[1][i].clear(),has[i]=0;
      while(m--){
         int a=read() , b=read();
         if((n&1)&&b==nn+1){add(a,b,1);
            has[a]=true;
            if(a!=b)add(b,a,1);
            int aa = n - a + 1  , bb = n - b + 1;
            if(aa!=a)add(aa,b,1),add(b,aa,1);
            continue;
         }if(n&1)A.emplace_back(pii(a,b));
         if(a!=b)add(b,a,0);add(a,b,0);
      }LL ans = 1LL*n*n*n+work(0);
      if(n&1)ans += add() - 12LL * all[0] + work(1);
      printf("%lld\n",ans);
   }
   return 0;
}





阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页