CF461D Complicated Task

2.5寒假训练 Complicated Task (Standard IO)
Time Limits: 1000 ms Memory Limits: 262144 KB
Description
Description
Input
Input
Output
Output
Sample Input

3 2
1 1 x
2 2 o

Sample Output

2

Data Constraint
对于30%的数据,N<=15
对于100%的数据,N,K<=10^5


解题思路

已知了第一行,就能知道整幅图的样子了:
假设第i行j个为 f[i][j] f [ i ] [ j ] 那么为了满足 (i1,j) ( i − 1 , j ) 满足条件,有

f[i][j]f[i1][j1]f[i1][j+1]f[i2][j]=0 f [ i ] [ j ] ⨁ f [ i − 1 ] [ j − 1 ] ⨁ f [ i − 1 ] [ j + 1 ] ⨁ f [ i − 2 ] [ j ] = 0
也就是
f[i][j]=f[i1][j1]f[i1][j+1]f[i2][j] f [ i ] [ j ] = f [ i − 1 ] [ j − 1 ] ⨁ f [ i − 1 ] [ j + 1 ] ⨁ f [ i − 2 ] [ j ]

观察图与第一行的关系:
Analysis
像这样黑白格分块,每一个黑格都对应着第一行某连续子黑格的异或,算出构成格子 (x,y) ( x , y ) 的异或区间为 (1,(max{xy,yx}1,min{2nxy+1,x+y1}]) ( 1 , ( max { x − y , y − x } − 1 , min { 2 n − x − y + 1 , x + y − 1 } ] )
想到 i(l,r]a[x]=S[l]S[r] ⨁ i ∈ ( l , r ] a [ x ] = S [ l ] ⨁ S [ r ] (其中 S[x]=i[0,x]a[x] S [ x ] = ⨁ i ∈ [ 0 , x ] a [ x ]
(x,y) ( x , y ) 已知时,令 l=max{xy,yx}1,r=min{2nxy+1,x+y1} l = max { x − y , y − x } − 1 , r = min { 2 n − x − y + 1 , x + y − 1 }
a(x,y)=1(o) a ( x , y ) = 1 ( ′ o ′ ) S[l]xorS[r]=1 S [ l ] x o r S [ r ] = 1 S[l]S[r] S [ l ] ≠ S [ r ]
同理若 a(x,y)=0(x) a ( x , y ) = 0 ( ′ x ′ ) S[l]=S[r] S [ l ] = S [ r ] 知道了所有 S[] S [ ] 通过异或可以知道第一行,进而知道整个矩阵。

问题转化成了给出相等与不相等的限制,输出方案数,并查集维护。
将每个点分裂成两个x0,x1
l0与r0、l1与r1连通表示S[l]=S[r]
l1与r0、r1与l0连通表示S[l]≠S[r]
若限制矛盾,输出0,
答案一定为 2k 2 k k为不在非含0联通块的联通块个数(S[0]=0)

#include<cstring>
#include<cstdio>
#include<algorithm>
#define N 100100
#define mo 1000000007

using namespace std;

int fa[N+N],k,n;
bool p=1;

int get(int x){return x==fa[x]?x:(fa[x]=get(fa[x]));}
void mersame(int x,int y){
    int a0=get(x+x-1),a1=get(x+x),b0=get(y+y-1),b1=get(y+y);
    if(a0==b1 || a1==b0)p=0;else fa[b0]=a0,fa[b1]=a1;
}
void merdiff(int x,int y){
    int a0=get(x+x-1),a1=get(x+x),b0=get(y+y-1),b1=get(y+y);
    if(a0==b0 || a1==b1)p=0;else fa[b1]=a0,fa[b0]=a1;
}

int main(){
    scanf("%d %d",&n,&k);
    for(int i=1;i<=n+n+4;i++)fa[i]=i;
    for(int i=1;i<=k;i++){
        int x,y;scanf("%d %d ",&x,&y);char c=getchar();
        int h=max(x-y,y-x)+1,t=min(2*n-x-y+1,x+y-1)+2;
        if(c=='o')merdiff(h,t);else mersame(h,t);
        if(!p)break;
    }
    if(p){
        int ans=1;
        for(int i=1;i<=n+n+4;i++)get(i);
        for(int i=5;i<=n+n+4;i+=2)
            if(fa[i]==i && i!=fa[1] && i!=fa[2] && i!=fa[3] && i!=fa[4])ans=ans*2%mo;
        printf("%d",ans);
    }else printf("0");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值