Educational Codeforces Round 123 (Rated for Div. 2) D. Cross Coloring

Problem - D - Codeforces

翻译:

有一张纸,可以用大小为𝑛×𝑚:𝑛行和𝑚列的单元格表示。所有的细胞最初都是白色的。

𝑞操作已应用到工作表。他们的𝑖-th可以描述如下:

𝑥𝑖𝑦𝑖-选择一个𝑘非白色和颜色的整个行𝑥𝑖和整个列𝑦𝑖。新颜色应用于每个单元格,而不管该单元格在操作之前是否被着色。
应用所有𝑞操作后的纸张称为着色。如果存在至少一个单元格以不同的颜色着色,则两种着色是不同的。

有多少种不同的颜色?打印数字模998244353。

输入
第一行包含一个整数𝑡(1≤𝑡≤104)——测试用例的数量。

测试用例的第一行包含四个整数𝑛、𝑚、𝑘和𝑞(1≤𝑛,𝑚,𝑘,𝑞≤2⋅105)——纸张的大小、非白色颜色的数量和操作的次数。

下面的𝑞行中的𝑖-th包含了对𝑖-th操作的描述—两个整数𝑥𝑖和𝑦𝑖(1≤𝑥𝑖≤𝑛;1≤𝑦𝑖≤𝑚)—操作应用到的行和列。

𝑞对所有测试用例的和不超过2⋅105。

输出
对于每个测试用例,打印一个整数——对998244353模的不同颜色的数量。

例子
inputCopy
2
1 1 3 2
1
1
2 2 2 3
2 1
1
2 - 2
outputCopy
3.
4

思路:

根据已给的顺序来进行涂颜色,然后最后计算有多少种不同颜色的方案。正着模拟,我们就需要全部模拟一下,然后再bfs/dfs查找连通块的数量。数据范围过大会直接T掉。正难则反,我们倒着来的话,会发现我们只需要记录每行每列的数量就可以了,如果满足了行或者列就可以break,因为是最后涂的,所以不用担心被覆盖。

代码:

#include <iostream>
#include <algorithm>
#include <string.h>
#include <string>
#include <math.h>
#include <stdio.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<tuple>
#include<numeric>
#include<stack>
using namespace::std;
typedef long long  ll;
int n,t;
inline __int128 read(){
    __int128 x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if(ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
inline void print(__int128 x){
    if(x < 0){
        putchar('-');
        x = -x;
    }
    if(x > 9)
        print(x / 10);
    putchar(x % 10 + '0');
}
const ll mod=998244353;
int m,k,q;
struct we{
    int x,y;
}c[200005];
bool h[200005],l[200005];
ll ksm(ll x,ll y){
    ll oper=1;
    while (y) {
        if (y&1) {
            oper=oper*x%mod;
        }
        x=x*x%mod;
        y>>=1;
    }
    return oper%mod;
}
void solv(){
    cin>>n>>m>>k>>q;
    
    for (int i =1; i<=n; i++) {
        h[i]=false;
    }
    for (int i =1; i<=m; i++) {
        l[i]=false;
    }
    
    for (int i=0; i<q; i++) {
        cin>>c[i].x>>c[i].y;
    }
    int na=0;
    int h1=0,l1=0;
    for (int i=q-1; i>=0; i--) {
        if (l1==m||h1==n) {
            break;
        }
        if (h[c[i].x]&&l[c[i].y]) {
            continue;
        }
        
        if (!h[c[i].x]) {
            h[c[i].x]=true;
            h1++;
        }
        if (!l[c[i].y]) {
            l[c[i].y]=true;
            l1++;
        }
        na++;
    }
    printf("%lld\n",ksm(k, na));
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(); cout.tie();
    cin>>t;
    while (t--) {
        solv();
    }
    return 0;
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值