2011-09-16 06:55:23Morris

d572. 第六題:柏油我認識妳嗎之似曾不相識

d572. 第六題:柏油我認識妳嗎之似曾不相識

內容 :

本題絕對是超越UVrongAnswer-online-judge,NPXC……歷屆爛梗考古題的超級有梗題。 

據某板中G姓要用弱者許胖在全國賽模式,難度調CRAZY(對手都是王X博)連續破台三次,才會有5%機率出現的隱藏人物有言:「這題是『世界宇宙無敵超級究極黃金必殺最強牛B好囧腹黑傲嬌三次方』的有梗題,若將該題目用來報科展絕對可以得到全國一等獎XDDDD。」 

由於本題的梗實在太高了,只有智商>180才看得懂,智商低於100的人只要每天定期對本題膜拜個3次嘴裡大喊:「我是柏油控!」就能增加0.01%IQ 

題目敘述如下: 

小蔡是一個柏油控,他擁有一塊矩形的私人柏油地,並由n條水平線及m條鉛直線分割成(m+1)*(n+1)塊等大的區域。 

有一天小蔡想在不同區塊漆上四種不同的顏色,並規定相鄰的兩塊不能漆上同一顏色,兩個區塊被視為相鄰只有當兩區塊由一條共同的邊組成,且有些區塊會被指定為不漆顏色(其餘皆要漆色),請你計算出總共有幾種上色的方法?

輸入說明 :

輸入第一行為一個整數T(T<=50)表以下有幾組測資數。

一組測資將會從兩個整數M,N開始(0<=M,N<=6)為用來分割的鉛垂線數,及水平線數。

下一行為一個整數K表以下有幾個不用上色的格子座標。

接下來的K行為兩個整數x,y(1<=x<=M+1,1<=y<=N+1)及該格子的座標。

且每個座標都是唯一的不會重複。

輸出說明 :

對於每組測資請以"Case #: P"的格式輸出於一行,#表對應第幾組輸入測資,P為該測資的矩形地的總上色方法數。注意:輸出的答案要mod1000000007。

範例輸入 :

2
1 1
1
2 1
0 0
0

範例輸出 :

Case 1: 36
Case 2: 4

提示 :

5/9修正題目敘述

出處 :

板擦高中柏油杯inker出題、UVa改編 (管理:m80126colin)




作法 : DP
此題與 d664. 11725 - Colorful Board 相同

/**********************************************************************************/
/*  Problem: d572 "第六題:柏油我認識妳嗎之似曾不相識" from 板擦高中柏油杯inker出題、UVa改編*/
/*  Language: C (1684 Bytes)                                                      */
/*  Result: AC(280ms, 912KB) judge by this@ZeroJudge                              */
/*  Author: morris1028 at 2011-09-15 16:18:52                                     */
/**********************************************************************************/


#include<stdio.h>
#include<string.h>
void change(int n, char *s) {
    if(n == 0) return;
    change(n/5, s+1);
    *s = n%5;
}
int Calu(int n, char *s) {
    if(n == 0) return 0;
    return Calu(n-1, s+1)*5+(*s);
}
main() {
    int T, n, m, K, x, y, C = 1;
    int map[8][8], s5[10] = {1};
    int i, j, k, l;
    for(i = 1; i < 10; i++)
        s5[i] = s5[i-1]*5;
    scanf("%d", &T);
    while(T--) {
        scanf("%d %d", &m, &n);
        scanf("%d", &K);

        memset(map, 0, sizeof(map));
        for(i = 0; i < K; i++) {
            scanf("%d %d", &x, &y);
            map[x][y] = 1;
        }
        m++, n++;
        int last[78126], now[78126];
        int state = s5[n]-1, tmp, now_state;
        char CH[10];
        memset(last, 0, sizeof(last));
        last[0] = 1;
        for(i = 0; i < m; i++) {
            for(j = 1; j <= n; j++) {
                for(k = 0; k <= state; k++) {
                    memset(CH, 0, sizeof(CH));
                    change(k, CH);
                    if(last[k] == 0)    continue;
                    if(j != 1 && CH[j-2] == 0 && map[i+1][j-1] == 0)    continue;
                    if(j != 1 && CH[j-2] != 0 && map[i+1][j-1] != 0)    continue;
                    if(map[i+1][j]) {
                        CH[j-1] = 0;
                        now_state = Calu(n, CH);
                        now[now_state] = (now[now_state] + last[k])%1000000007;
                    } else {
                        for(l = 1; l <= 4; l++) {
                            if(CH[j-1] != l && (j == 1 || CH[j-2] != l)) {
                                tmp = CH[j-1], CH[j-1] = l;
                                now_state = Calu(n, CH);
                                now[now_state] = (now[now_state] + last[k])%1000000007;
                                CH[j-1] = tmp;
                            }
                        }
                    }
                }
                for(k = 0; k <= state; k++)
                    last[k] = now[k];
                memset(now, 0, sizeof(now));
            }
        }
        int Ans = 0;
        for(i = 0; i <= state; i++)
            Ans = (Ans+last[i])%1000000007;
        printf("Case %d: %d\n", C++, Ans);
    }
    return 0;
}