奇偶数

1221: 奇偶数

时间限制: 1 Sec  内存限制: 128 MB

提交: 6  解决: 3

[提交][状态][讨论版]

题目描述

TomBob在玩一个游戏:他写一个由01组成的序列。

Tom选其中的一段(比如第3位到第5位),问他这段里面有奇数个1还是偶数个1Bob回答你的问题,然后Tom继续问。

Bob有可能在撒谎。Tom要检查Bob的答案,指出在Bob的第几个回答一定有问题。

有问题的意思就是存在一个01序列满足这个回答前的所有回答,而且不存在序列满足这个回答前的所有回答及这个回答。

输入

1行一个整数,是这个01序列的长度(<=1000000000)

2行一个整数,是问题和答案的个数。

3行开始是问题和答案,每行先有两个整数,表示你询问的段的开始位置和结束位置。

然后是Bob的回答。odd表示有奇数个1even表示有偶数个1

输出

输出一行,一个数X,表示存在一个01序列满足第1到第X个回答,但是不存在序列满足第1到第X+1个回答。如果所有回答都没问题,你就输出所有回答的个数。

样例输入

10
5
1 2 even
3 4 odd
5 6 even
1 6 even
7 10 odd

样例输出

3

提示

【样例说明】

4条与之前有矛盾,前3条没问题

【数据规模和约定】

最多10000个问题

题解:

  看题目很容易想到并查集,但手动算了一下样例后发现,此题并没那么容易。。

这里的x,y指的是x-y区间内1的奇偶。普通的关系类并查集都是合并成同一个父亲

的。但这题的1,2和3,4实际上是可以合并为1,4的。。

  我的解决方法是将1,2改为1,3,即x,y改为x,y+1,改变后的区间右端点实际上是不

取到的,这样一来问题也就容易了,当然由于01长度会很大,需要离散化。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
struct node
{
    int a,id;
}p[10005];
char s[10005][15];
int T,n,i,k,ans,x,y,fx,fy,a[10005],h[20005],f[20005],dis[20005];
bool cmp(const node&x,const node&y)
{
    return x.a<y.a;
}
int get(int x)
{
    if(f[x]==x) return x;else
    {
        int y=get(f[x]);
        dis[x]=(dis[f[x]]+dis[x])%2;
        return f[x]=y;
    }
}
int main()
{
    scanf("%d%d",&T,&n);
    for(i=1;i<=n;i++)
    {
        scanf("%d%d%s",&p[i*2-1].a,&p[i*2].a,s[i]);
        p[i*2].a++;
        p[i*2-1].id=i*2-1;
        p[i*2].id=i*2;
    }
    sort(p+1,p+2*n+1,cmp);
    p[0].a=-1;
    for(i=1;i<=2*n;i++)
    {
        if(p[i].a!=p[i-1].a) k++;
        h[p[i].id]=k;
    }
    for(i=1;i<=2*n;i++)
        f[i]=i;
    for(i=1;i<=n;i++)
    {
        x=h[i*2-1];
        y=h[i*2];
        fx=get(x);
        fy=get(y);
        if(fx==fy)
        {
            if(s[i][0]=='o'&&(dis[x]-dis[y]+2)%2==0) break;
            if(s[i][0]=='e'&&(dis[x]-dis[y]+2)%2==1) break;
        }
        if(s[i][0]=='o')
        {
            f[fy]=fx;
            dis[fy]=(dis[x]+dis[y]+1)%2;
        } else
        {
            f[fy]=fx;
            dis[fy]=(dis[x]+dis[y])%2;
        }
        ans=i;
    }
    printf("%d",ans);
    return 0;
}
bzoj1202狡猾的商人也是类似的做法,不过更为简单。。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值