大杀器Bitset

其实并不怎么会用,有一次有位学长提到了这个名字,就这么取题目了。

1.BZOJ 3687 简单题

求子集的算术和的异或和

http://www.lydsy.com/JudgeOnline/problem.php?id=3687

我们并不需要知道每个数(和)出现了多少次,只需知道它出现了奇数次还是偶数次,于是用一个二进制串表示。初始化dp[0]=1;

加进一个数x,在原先集合的基础上,每个数+x出现的次数会++,就直接异或上集合左移x

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<bitset>
using namespace std;
const int maxn=2000000+299;
bitset<maxn>b;
int n,x,sum,ans;
int main()
{
   scanf("%d",&n);
   b[0]=1;
   while(n--){
       scanf("%d",&x);
       sum+=x;
       b^=(b<<x);
   }
   for(int i=1;i<=sum;i++)
    if(b[i])
      ans^=i;
   printf("%d\n",ans);
   return 0;
}
BZOJ 3687 简单题

 

2.BZOJ 4478 侦探jyy

一开始我和SXY大佬都写了一种神奇地求出一个top即某两个点的上面的一个交点来判断是否一定发生的算法,虽然SXY的算法比我不知道高到哪里去了。骗了50分。然后轩神说,会有这种神奇的情况,没有交点,但是C发生了D一定发生

 

于是正解是,对于每个发生的事件,向前跑一遍会导致它发生的集合,然后这些集合的交集即为答案。

这个就可以用Bitset来搞。

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<bitset>
const int N=1000+29;
const int M=100000+29;
using namespace std;
bitset<N>d[N],ans;
int xx,x,y,cntz,cntf,n,m,D,firz[N],nxtz[M],toz[M],firf[N],nxtf[M],tof[M],vis[N];
inline int read(){
    char ch=getchar(); int ret=0,f=1;
    while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
    return ret*f;
}
void addz(int u,int v){
    nxtz[++cntz]=firz[u]; firz[u]=cntz; toz[cntz]=v;
}
void addf(int u,int v){
    nxtf[++cntf]=firf[u]; firf[u]=cntf; tof[cntf]=v;
}
void dfs1(int x){
    vis[x]=1; d[x][x]=1;
    for(int i=firz[x];i;i=nxtz[i]){
        if(!vis[toz[i]])
            dfs1(toz[i]);
        d[x]|=d[toz[i]];
    }
}
void dfs2(int x){
    vis[x]=1;  //d[x][x]=1;
    bitset<N>tmp;
    if(firf[x]){
        if(!vis[tof[firf[x]]]) dfs2(tof[firf[x]]);
        tmp=d[tof[firf[x]]];
    }
    else return;
    for(int i=nxtf[firf[x]];i;i=nxtf[i]){
        if(!vis[tof[i]]) dfs2(tof[i]);
        tmp&=d[tof[i]];
    }
    d[x]|=tmp;
}
int main()
{
   freopen("a.in","r",stdin);
   freopen("a.out","w",stdout);
   n=read(); m=read(); D=read();
   for(int i=1;i<=m;i++){
       x=read(); y=read();
       x--; y--;
       addz(x,y);
       addf(y,x);
   }
   for(int i=0;i<n;i++)
    if(!vis[i]) dfs1(i);
   memset(vis,0,sizeof(vis));
   for(int i=1;i<=D;i++){
       scanf("%d",&xx); xx--;
       if(!vis[xx]) dfs2(xx);
       ans|=d[xx];
   }
   for(int i=0;i<n;i++){
       if(ans[i])
        printf("%d ",i+1);
   }
   return 0;
}
BZOJ 4478 侦探jyy

 

有人提供了一种神奇的算法,枚举每个不是发生点的点,把它标记为未发生,然后再这个限制条件下跑一遍看是否所以发生点都可以发生,若不能则此点一定发生。时间复杂度好像没保证,不过这个随机数据过掉了。

posted @ 2017-09-04 17:15  啊宸  阅读(1348)  评论(0编辑  收藏  举报