大杀器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

 

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


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM