[2018-2019 ACM-ICPC, Asia Dhaka Regional Contest] H Tile Game(模擬,迴圈節)
阿新 • • 發佈:2020-11-06
[2018-2019 ACM-ICPC, Asia Dhaka Regional Contest] H Tile Game(模擬,迴圈節)
題面:
題意:
給定一個數字迷盤,每一個# 字元代表一種不同的顏色。
我們可以對迷盤進行上下左右四種操作,分別表示將迷盤中的數字按方向平行移動到對應方向。
我們當所有數字都在左下角,我們稱為是一個穩定的狀態。
現在給你一個穩定的迷盤,你可以做任意方向操作任意次,問你能得到多少種迷盤?
當有數字在不同的位置時,我們稱為該迷盤不同。
思路:
我們設一組“上右下左”是一個正迴圈,一組“右上左下”是一個負迴圈。
我們可以知道一個穩定的狀態先正迴圈,再來一次負迴圈之後,會回到原狀態。
那麼我們想得到更多的不同狀態,就到一直正迴圈(或者一直負迴圈)移動。
並且所有的穩定狀態的形狀都是相同的。
通過分析發現,不同的數字之間構成一個迴圈圈,且會存在多少個迴圈圈的情況,
設第\(\mathit i\)個圈的長度為\(C_i\),那麼這些圈能構成的所有狀態就是\(LCM(C_i)\),道理和多個迴圈節求公共迴圈節一樣。
那麼我們模擬正迴圈一下,通過數字的座標變換看一下圈的資訊,然後求出答案即可。
因為涉及到取模,而普通取lcm的演算法不能進行取模運算。所以我們用唯一分解定理將每一個數分成為不同質數的冪次積形式,然後對每一個質因子冪次取最大值即可。(lcm的本質意義)
程式碼:
#include <iostream> #include <cstdio> #include <algorithm> #include <bits/stdc++.h> #define ALL(x) (x).begin(), (x).end() #define sz(a) int(a.size()) #define rep(i,x,n) for(int i=x;i<n;i++) #define repd(i,x,n) for(int i=x;i<=n;i++) #define pii pair<int,int> #define pll pair<long long ,long long> #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) #define MS0(X) memset((X), 0, sizeof((X))) #define MSC0(X) memset((X), '\0', sizeof((X))) #define pb push_back #define mp make_pair #define fi first #define se second #define eps 1e-6 #define chu(x) if(DEBUG_Switch) cout<<"["<<#x<<" "<<(x)<<"]"<<endl #define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c)) #define du2(a,b) scanf("%d %d",&(a),&(b)) #define du1(a) scanf("%d",&(a)); using namespace std; typedef long long ll; ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;} ll lcm(ll a, ll b) {return a / gcd(a, b) * b;} ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;} ll poww(ll a, ll b) { if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a ;} a = a * a ; b >>= 1;} return ans;} void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}} void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}} inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;} inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;} void pvarr_int(int *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%d%c", arr[i], i == n ? '\n' : ' ');}} void pvarr_LL(ll *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%lld%c", arr[i], i == n ? '\n' : ' ');}} const int maxn = 40010; const int inf = 0x3f3f3f3f; /*** TEMPLATE CODE * * STARTS HERE ***/ #define DEBUG_Switch 0 int n, m; int minfac[maxn]; std::vector<int> prime; void init_prime() { for (int i = 2; i < maxn; ++i) { if (!minfac[i]) { minfac[i] = i; prime.push_back(i); } for (auto u : prime) { if (1ll * i * u >= maxn) { break; } minfac[i * u] = u; if (minfac[i] % u == 0) { break; } } } /* O(log(cnt))唯一分解 cnt while (cnt > 1) { int tmp = minfac[cnt]; int ccnt = 0; while (cnt % tmp == 0){ ++ ccnt; cnt /= tmp; } //tmp^ccnt; } */ } char s[202][202]; int a[202][202]; int b[202][202]; void up() { repd(j, 1, m) { int num = 0; for (int i = 1; i <= n; ++i) { if (a[i][j] == 0) { num++; } else { break; } } repd(i, 1, n) { if (a[i][j] != 0) { a[i - num][j] = a[i][j]; if (num) a[i][j] = 0; } } } } void down() { repd(j, 1, m) { int num = 0; for (int i = n; i >= 1; --i) { if (a[i][j] == 0) { num++; } else { break; } } for (int i = n; i >= 1; --i) { if (a[i][j] != 0) { a[i + num][j] = a[i][j]; if (num) a[i][j] = 0; } } } } void left() { repd(i, 1, n) { int num = 0; for (int j = 1; j <= m; ++j) { if (a[i][j] == 0) { num++; } else { break; } } for (int j = 1; j <= m; ++j) { if (a[i][j] != 0) { a[i][j - num] = a[i][j]; if (num) a[i][j] = 0; } } } } void right() { repd(i, 1, n) { int num = 0; for (int j = m; j >= 1; --j) { if (a[i][j] == 0) { num++; } else { break; } } for (int j = m; j >= 1; --j) { if (a[i][j] != 0) { a[i][j + num] = a[i][j]; if (num) a[i][j] = 0; } } } } int max_pow[maxn]; int vis[maxn]; pii pos[maxn]; const ll mod = 78294349ll; void solve() { MS0(vis); MS0(max_pow); int id = 0; repd(i, 1, n) { repd(j, 1, m) { if (s[i][j] == '.') { a[i][j] = 0; } else { a[i][j] = ++id; } b[i][j] = a[i][j]; } } up(); right(); down(); left(); repd(i, 1, n) { repd(j, 1, m) { if (b[i][j] > 0) { pos[b[i][j]] = mp(i, j); } } } repd(i, 1, id) { if (vis[i]) { continue; } pii temp = pos[i]; int now = a[temp.fi][temp.se]; int num = 1; while (now != i) { num++; temp = pos[now]; now = a[temp.fi][temp.se]; } while (num > 1) { int cnt = 0; int fac = minfac[num]; while (num % fac == 0) { num /= fac; cnt++; } max_pow[fac] = max(cnt, max_pow[fac]); } } ll ans = 1ll; repd(i, 2, maxn - 1) { if (max_pow[i] > 0) { ans = ans * powmod(i, max_pow[i], mod) % mod; } } printf("%lld\n", ans ); } int main() { #if DEBUG_Switch freopen("C:\\code\\input.txt", "r", stdin); #endif //freopen("C:\\code\\output.txt","w",stdout); int t; init_prime(); t = readint(); for (int icase = 1; icase <= t; ++icase) { n = readint(); m = readint(); repd(i, 1, n) { scanf("%s", s[i] + 1); } printf("Case %d: ", icase ); solve(); } return 0; }