容斥 + 爆搜打表 ---- 2020年南京icpc H.Harmonious Rectangle

题目链接


题目大意:

就是给你一个二维平面 { ( x , y ) ∣ 1 ≤ x ≤ n , 1 ≤ y ≤ m } \{(x,y)|1\leq x\leq n,1\leq y \leq m\} {(x,y)1xn,1ym},你现在有3种颜色,你可以给写平面的点涂上颜色,问你至少存在4个点 ( x 1 , y 1 ) , ( x 2 , y 2 ) , ( x 1 , y 2 ) , ( x 2 , y 1 ) (x1,y1),(x2,y2),(x1,y2),(x2,y1) (x1,y1),(x2,y2),(x1,y2),(x2,y1)使得
color(x1,y1)=color(x1,y2)&&color(x2,y1)=color(x2,y2) \text{color(x1,y1)=color(x1,y2)\&\&color(x2,y1)=color(x2,y2)} color(x1,y1)=color(x1,y2)&&color(x2,y1)=color(x2,y2)
or \text{or} or
color(x1,y1)=color(x2,y1)&&color(x1,y2)=color(x2,y2) \text{color(x1,y1)=color(x2,y1)\&\&color(x1,y2)=color(x2,y2)} color(x1,y1)=color(x2,y1)&&color(x1,y2)=color(x2,y2)

的涂色方法有多少种?
输出方案数 mod ( 1 e 9 + 7 ) \text{mod}(1e9+7) mod(1e9+7)


解题思路:

首先颜色数这么少?
那么根据容斥原理两两组合最多就9种情况,就是如果 m a x { n , m } ≥ 9 max\{n,m\}\ge9 max{n,m}9那么随便涂肯定有解!!
在这里插入图片描述
那么就好办了:
对于 m a x { n , m } < 9 max\{n,m\}<9 max{n,m}<9我们可以直接爆搜打不合法矩阵的表。
打了表直接快速幂即可细节见代码:
注意坑点是: n==1||m==1 \text{n==1||m==1} n==1||m==1是没结果的


ACcode

#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 7;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
   x = 0;char ch = getchar();ll f = 1;
   while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
   while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {
   read(first);
   read(args...);
}

int mat[9][9] = {
{3,9,27,81,243,729,2187,6561,19683},
{9,66,390,1800,6120,13680,15120,0,0},
{27,390,3198,13176,27000,13680,15120,0,0},
{81,1800,13176,24336,4320,0,0,0,0},
{243,6120,27000,4320,4320,0,0,0,0},
{729,13680,13680,0,0,0,0,0,0},
{2187,15120,15120,0,0,0,0,0,0},
{6561,0,0,0,0,0,0,0,0},
{19683,0,0,0,0,0,0,0,0},
};
int col[15][15];
bool vis[15][15];
int limx, limy;
inline int dfs(int x, int y) { //打表代码
    int ans = 0;
    for(int i = 1; i <= 3; ++ i) {
        col[x][y] = i;
        bool flag = 1;
        for(int j = x-1; j >= 1; -- j) {
            for(int z = y-1; z >= 1 && flag; -- z) {
                if(col[x][y] == col[j][y] && col[x][z] == col[j][z]) flag = 0;
                if(col[x][y] == col[x][z] && col[j][y]  == col[j][z]) flag = 0;
            }
            if(flag == 0) break;
        }
        if(flag) {
            if(x==limx&&y==limy) {
                ans ++;
            }
            else if(x==limx) ans += dfs(1,y+1);
            else ans += dfs(x+1,y);
        }
    }
    return ans;
}

inline ll qim(ll a, ll b) {
    ll res = 1;
    while(b) {
        if(b & 1) res = res * a % mod;
        b >>= 1;
        a = a * a % mod;
    }
    return res;
}

int main() {
    IOS;
    // for(int i = 1; i <= 9; ++ i)
    //   for(int j = 1; j <= 9; ++ j) {
    //       ms(col,0);
    //       limx = i, limy = j;
    //       mat[i][j] = dfs(1,1);
    //   } 
    // for(int i = 1; i <= 9; ++ i) {
    //    cout << "{";
    //    for(int j = 1; j <= 9; ++ j) {
    //        cout << mat[i][j];
    //        if(j==9) cout << "},\n";
    //        else cout << ",";
    //    }
    // }
    int T;
    cin >> T;
    while(T--) {
        int n, m;
        cin >> n >> m;
        if(n == 1 || m == 1) cout << "0\n";
        else if(n <= 9 && m <= 9){
        // 总的减去不合法的
            cout << ((qim(3,n*m) - mat[n-1][m-1]) % mod + mod) % mod << endl;
        } else cout << qim(3,n*m) % mod << endl;
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值