1. 程式人生 > >2017 ACM區域賽現場賽 青島站 E (polya計數)

2017 ACM區域賽現場賽 青島站 E (polya計數)

amp mod 循環 等價 img cout es2017 範圍 知乎

題目鏈接(暫無)

吐槽:這場比賽感覺對我感覺還算友好,雖然Q群知乎上命題方已經被噴死了,C語言上機題還有字符串題有大腿隊友輕松搞定,網絡流恰是我能想出來的,E本來也應該是在能力範圍內,不過因為之前沒寫過跑程序搜置換的題,一時看到就發怵。。萬幸過掉了K題網絡流拿到了金,不然場上沒寫E打銅得後悔死我。。

題意:一個3*3*1的長方體,有3*3(頂面)+3*4(側面)+3*3(底面)=30個待染色的小面,長方體有四個可扭動的軸,位於四條邊的中間那個1*1*1的小塊,每次可扭動180°。支持的基本的置換為上下翻轉,繞中心旋轉,將3*1*1的邊繞軸扭動。給定顏色數c和模數p,求總的非等價染色方案數模p的結果。

爆搜求置換;對每種置換求循環指數,從而得到循環指數為k(1<=k<=30)的循環個數;套用Polya公式

技術分享

(註意p可能非質數所以會有一個特殊處理,見下圖(tot為置換總數))

技術分享

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef __int128 LLL;

const int N=30;
int ori[N]= {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29
}; int tr[3][N]= { // { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20, 21,22,23,24,25,26,27,28,29}, {29,25,24,23,22,21,28,27,26, 16,15,14,13,12,11,10,9 ,20,19,18,17, 5, 4, 3, 2, 1, 8, 7, 6, 0}, {0,3,4,5,6,7,8,1,2, 12,13,14,15,16,17,18,19,20,9 ,10
,11, 23,24,25,26,27,28,21,22,29}, {0,23,22,21,4,5,6,7,8, 13,12,11,10,9 ,14,15,16,17,18,19,20, 3 ,2 ,1 ,24,25,26,27,28,29} }; int ans[1600][N]; int tot; void dfs(int cur) { for(int i=0; i<3; i++) { int temp[N]; for(int j=0; j<N; j++) temp[j]=ans[cur][tr[i][j]]; int flag=1; for(int k=0; k<tot; k++) { int flag1=1; for(int j=0; j<N; j++) if(ans[k][j]!=temp[j]) flag1=0; if(flag1) //flag1=true 表示 temp和某個ans[k]全等 { flag=0; break; } } if(flag) //flag=true 表示 temp和任意ans[k]不全等 { for(int j=0; j<N; j++) ans[tot][j]=temp[j]; tot++; dfs(tot-1); } } } int cnt[N]; int vis[N]; void dfs2(int x,int y[]) { vis[x]=1; if(!vis[y[x]]) dfs2(y[x],y); } void add(int y[]) { memset(vis,0,sizeof(vis)); int t=0; for(int i=0;i<N;i++) if(!vis[i]) { t++; dfs2(i,y); } cnt[t]++; } LLL qpow(LLL x,LLL n,LLL mod) { LLL ret=1; for(;n;n>>=1) { if(n&1) ret=ret*x%mod; x=x*x%mod; } return ret; } LLL qpow(LLL x,LLL n) { LLL ret=1; for(;n;n>>=1) { if(n&1) ret=ret*x; x=x*x; } return ret; } int main() { for(int i=0; i<N; i++) ans[0][i]=ori[i]; tot++; dfs(0); printf("%d\n",tot); printf("\n========================================\n\n"); for(int i=0;i<tot;i++) add(ans[i]); for(int i=1;i<=N;i++) printf("%2d : %d\n",i,cnt[i]); printf("\n========================================\n\n"); LL c,p; while(cin>>c>>p) { LLL sum=0; LLL b=tot*p; // for(int i=1;i<=N;i++) // sum+=cnt[i]*qpow(c,i); // sum/=tot; // cout<<(LL)(sum%p)<<endl; for(int i=1;i<=N;i++) sum=(sum+cnt[i]*qpow(c,i,b))%b; sum/=tot; cout<<(LL)sum<<endl; } }

2017 ACM區域賽現場賽 青島站 E (polya計數)