BZOJ3421: Poi2013 Walk

来源:互联网 发布:centos7网络配置命令 编辑:程序博客网 时间:2024/04/27 05:27

题目大意:有2n个长度为n的01串,两个01串之间有边当且仅当这两个01串只有一位不同,现在从这2n个串中拿掉k个,问指定两个串之间能否到达

吐槽:
先给这题100个差评,这题无论是POI官网还是BZOJ都特别差
先说POI官网,给的题解直接来了个定理也没证,然后说了一句这个定理在opisu中已经给出了,我拿百度翻译翻译了一下发现opisu是description 的意思…可是description 里没给啊,然后我就翻了整个POI2013的波兰文题解也没找到在哪,那就只能把这个定理当成已知了
再说BZOJ,这题总时限开50s,官网上单点都有120s好吗!各种卡常数,最后照着Claris的代码一点一点改,结果把循环变量i开成全局变量就A了…..卡了一上午测评差评!

题解:
先说那个POI官方给的题解里的定理吧,对于一个单位超立方体,如果我们把所有顶点划分成两个集合,这两个点集之间的边的数量至少是两个点集中较小的那一个的个数,也就是
|(u,v):uS,vVS|­­min(|S|,|VS|).
这个我也不会证,不过既然官方说这个题目里告知了,我们就把他当成定理吧

接着我们来证明对于一个单位超立方体,假如挖掉k个节点,剩下的结点个数大于nk的连通块至多有一个
用反证法
假设有两个这样的连通块,另S为其中一个连通块的点集,Vk为另一个的点集,则有VkVS|VS||Vk|nk+1
则由定理可知S与V-S这两个集合之间的边至少为nk+1条
接着因为一共删除了k个点,而每个点都向外连了n条边,所以最多最多只能删掉这nk+1条中的nk条边,也就是说S和V-S一定还有边相连,这就与之前假设的S是一个独立的连通块矛盾了
所以剩下的结点个数大于nk的连通块至多有一个

所以我们只需要从一个节点开始BFS,限制最多扩展nk步,如果两个都扩展了nk步还没搜完,那就说明他俩在同一个大块里
各种卡常数啊,unordered_map貌似都不行,只能手写hash链表

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define N 5001000#define M 9999991using namespace std;int i,head[M],nxt[N],cnt;long long v[N];inline void add(long long x){    int T=x%M,i;    cnt++;nxt[cnt]=head[T];    head[T]=cnt;v[cnt]=x;}long long q[N],h,t;inline void checkandadd(long long x){    int T=x%M,i;    for(int i=head[T];i;i=nxt[i])    if(v[i]==x) return;    cnt++;nxt[cnt]=head[T];    head[T]=cnt;v[cnt]=x;    t++;q[t]=x;}int n,k;char s[101];inline long long dec(){    scanf("%s",s);    long long ret=0,i;    for(int i=0;i<n;i++)    ret=ret*2+s[i]-48;    return ret;}long long S,E;long long a[N];int main(){    scanf("%d%d",&n,&k);    int nk=n*k+5;    long long x,y;    S=dec();    E=dec();    for(i=1;i<=k;i++)    {        a[i]=dec();        add(a[i]);    }    h=t=1;q[1]=S;    add(S);    while(h<=t&&t<=nk)    {        x=q[h];h++;        if(x==E) {puts("TAK");return 0;}        for(i=0;i<n;i++)        checkandadd(x^(1LL<<i));    }    if(t<=nk) {puts("NIE");return 0;}    h=t=1;q[1]=E;    cnt=0;    for(i=0;i<M;i++)    head[i]=0;    add(E);    for(i=1;i<=k;i++)    add(a[i]);    while(h<=t&&t<=nk)    {        x=q[h];h++;        if(x==S) {puts("TAK");return 0;}        for(i=0;i<n;i++)        checkandadd(x^(1LL<<i));    }    if(t<=nk) puts("NIE");    else puts("TAK");}
0 0
原创粉丝点击