题目链接H-Harmonious Rectangle_第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(南京)
题目描述
A vertex-colored rectangle is a rectangle whose four vertices are all painted with colors. For a vertex-colored rectangle, it's harmonious if and only if we can find two adjacent vertices with the same color, while the other two vertices also have the same color with each other.
For example,
,
and
are harmonious, while
is not (same number for same color, and different numbers for different colors).
For each point in
, where
is the set of all integers, Kotori wants to paint it into one of the three colors: red, blue, yellow. She wonders the number of different ways to color them so that there exists at least one harmonious rectangle formed by the points, whose edges are all parallel to the
- or
-axis. That is to say, there exists
and
such that
Two coloring plans are considered different if there exists a point having different colors in the two coloring plans.
For example,
![](https://i-blog.csdnimg.cn/blog_migrate/34411f2fa7b581f03abaf9ae3d076b39.png)
![](https://i-blog.csdnimg.cn/blog_migrate/307f06ac4c69a77c46c6dd9a8f01f5a4.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3bd6ccb19b3e51947c19e9676b08042c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/56c7da889a14d7bbc874b56d53e93e7b.png)
For each point in
![](https://i-blog.csdnimg.cn/blog_migrate/abb89be9dd94fb2d34d858547cbb181b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/943b03d62b9e0c6373ab3672a9af52b2.png)
![x](https://i-blog.csdnimg.cn/blog_migrate/6a70378a7cfd7a515a36ecdabd1e50b6.png)
![y](https://i-blog.csdnimg.cn/blog_migrate/77935ee341c08ef7b6cf7dc105b992c0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1b662b8aaf4aee494310f1eec033663e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/0e51aeda3d311679e1d2b6ffc9edc6f7.png)
![](https://i-blog.csdnimg.cn/blog_migrate/dda045897616bd5a2de6f00c8538b746.png)
or
![](https://i-blog.csdnimg.cn/blog_migrate/6102a3c60578bfffca232eb55540727b.png)
where
is the color of point
.
![](https://i-blog.csdnimg.cn/blog_migrate/6a3053e7c74b5f6e1c638aa0882932db.png)
![(x, y)](https://i-blog.csdnimg.cn/blog_migrate/95bca58df7b8082a0cf7001ed921370e.png)
输入描述:
There are multiple test cases. The first line of the input contains an integer(
) indicating the number of test cases. For each test case:
The first and only line contains three integers,
(
).
输出描述:
For each test case output one line containing one integer indicating the number of different ways of coloring modulo.
题目大意
给你一个n*m的矩阵,每个点都可以取三种颜色。问你有多少种染色方法可以使得矩阵中至少一对(x1,y1)与(x2,y2)满足下列式子。
(a[y1][x1] == a[y2][x1] && a[y1][x2] == a[y2][x2]) ||
(a[y1][x1] == a[y1][x2] && a[y2][x1] == a[y2][x2]))
分析
考虑在矩阵中选择任意两行a和b
a1 a2 a3 a4 a5 a6 ......
b1 b2 b3 b4 b5 b6 ......
可知(a1,b1)有3*3=9种组合方式。根据鸽笼原理,或者直接动脑子想想,可以想到当列数>9时,一定存在另一组(ai,bi)与(a1,b1)相同。同理,当行数>9时,一定存在两组相同的列。所以可以分类讨论:
- if n=1 || m=1 ,必为0
- else if n>9 || m>9,结果为 3 n ∗ m 3^{n*m} 3n∗m
- else 在9*9范围内,可以DFS剪枝搜索,然后把结果打个表。
打表用代码
分别用DFS剪枝和暴力穷举法实现。后者用来与前者在小范围时对拍。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mod_mul(ll a, ll b, ll n) {
a %= n; //优化后只要在开头模一次,其他的地方用if,效率提升近一倍
b %= n;
ll res = 0;
while (b) {
if (b & 1) {
res += a;
if (res > n) res -= n;
}
a += a;
if (a > n) a -= n;
b /= 2; //没开o2的话要换成b>>=1
}
return res;
}
ll mod_exp(ll a, ll b, ll n) {
ll res = 1;
a = a % n;
while (b) {
if (b & 1) res = mod_mul(res, a, n);
a = mod_mul(a, a, n);
b /= 2;
}
return res;
}
const ll MOD = 1e9 + 7;
const int MAXN = 12;
int a[MAXN][MAXN];
int n, m;
long long gcnt;
void get_next() {
const static int base = 3;
int carry = 1;
for (int i = n - 1; i >= 0; i--) {
for (int j = m - 1; j >= 0; j--) {
a[i][j] += carry;
carry = 0;
if (a[i][j] >= base) {
carry = a[i][j] / base;
a[i][j] %= base;
}
}
}
}
void print() {
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
printf("%d ", a[i][j]);
}
printf("\n");
}
printf("\n");
}
bool check() {
for (int y1 = 0; y1 < n; y1++) {
for (int x1 = 0; x1 < m; x1++) {
for (int y2 = y1 + 1; y2 < n; y2++) {
for (int x2 = x1 + 1; x2 < m; x2++) {
if ((a[y1][x1] == a[y2][x1] && a[y1][x2] == a[y2][x2]) ||
(a[y1][x1] == a[y1][x2] && a[y2][x1] == a[y2][x2]))
return true;
}
}
}
}
return false;
}
void dfs(int xx, int yy) {
for (int color = 0; color < 3; color++) {
int x2 = xx;
int y2 = yy;
a[y2][x2] = color;
bool flag = true;
for (int y1 = 0; y1 < y2 && flag; y1++) {
for (int x1 = 0; x1 < x2 && flag; x1++) {
if ((a[y1][x1] == a[y2][x1] && a[y1][x2] == a[y2][x2]) ||
(a[y1][x1] == a[y1][x2] && a[y2][x1] == a[y2][x2])) {
flag = false;
gcnt +=
mod_exp(3LL, (1LL * (n - 1 - y2) * (m) + (m - 1) - x2), MOD);
gcnt %= MOD;
}
}
}
if (flag) {
x2++;
if (x2 >= m) {
x2 = 0;
y2++;
if (y2 >= n){
continue;
}
}
dfs(x2, y2);
}
}
a[yy][xx]=-1;
}
ll solve_dfs(){
gcnt=0;
dfs(0,0);
return gcnt;
}
int solve_exhaust() {
int p = pow(3, n * m);
int cnt = 0;
for (int i = 0; i < p; i++) {
if (check()) {
cnt++;
// print();
}
// print();
get_next();
}
return cnt;
}
int main() {
for(n =1; n<=9;n++){
for(m=1;m<=9;m++){
if(m==1||n==1) printf("0, ");
else{
memset(a,0,sizeof(a));
printf("%lld, ",solve_dfs());
//printf("%lld, ",solve_exhaust());
}
}
printf("\n");
}
return 0;
}
AC代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD = 1e9+7;
int n,m;
ll mod_mul(ll a, ll b, ll n) {
a %= n; //优化后只要在开头模一次,其他的地方用if,效率提升近一倍
b %= n;
ll res = 0;
while (b) {
if (b & 1) {
res += a;
if (res > n) res -= n;
}
a += a;
if (a > n) a -= n;
b /= 2; //没开o2的话要换成b>>=1
}
return res;
}
ll mod_exp(ll a, ll b, ll n) {
ll res = 1;
a = a % n;
while (b) {
if (b & 1) res = mod_mul(res, a, n);
a = mod_mul(a, a, n);
b /= 2;
}
return res;
}
ll dat[9][9]={0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 15, 339, 4761, 52929, 517761, 4767849, 43046721, 387420489,
0, 339, 16485, 518265, 14321907, 387406809, 460338013, 429534507, 597431612,
0, 4761, 518265, 43022385, 486780060, 429534507, 792294829, 175880701, 246336683,
0, 52929, 14321907, 486780060, 288599194, 130653412, 748778899, 953271190, 644897553,
0, 517761, 387406809, 429534507, 130653412, 246336683, 579440654, 412233812, 518446848,
0, 4767849, 460338013, 792294829, 748778899, 579440654, 236701429, 666021604, 589237756,
0, 43046721, 429534507, 175880701, 953271190, 412233812, 666021604, 767713261, 966670169,
0, 387420489, 597431612, 246336683, 644897553, 518446848, 589237756, 966670169, 968803245};
int main() {
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
if(n==1||m==1){
printf("0\n");
}
else if(n<=9||m<=9){
n--;
m--;
printf("%lld\n",dat[n][m]%MOD);
}
else{
printf("%lld\n",mod_exp(3,1LL*n*m,MOD));
}
}
return 0;
}