其實並不怎么會用,有一次有位學長提到了這個名字,就這么取題目了。
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; }
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; }
有人提供了一種神奇的算法,枚舉每個不是發生點的點,把它標記為未發生,然后再這個限制條件下跑一遍看是否所以發生點都可以發生,若不能則此點一定發生。時間復雜度好像沒保證,不過這個隨機數據過掉了。

