Explosion HDU - 5036
题意:给出n个箱子。每个箱子上都有锁。一把钥匙只能开一把锁,一把锁只有一个钥匙。当然,对于有些没法用钥匙开的箱子,我们必须暴力打开。给出每个箱子中钥匙的数目和具体能开那个箱子,求暴力开箱子的数目的期望,使所有的箱子被打开。
心得:
- 期望的可加性。。http://blog.csdn.net/grooowing/article/details/45000205
感觉忘了挺多,因为这个地方总是以为期望是不可+的。
参考http://www.cnblogs.com/mengfanrong/p/5186386.html
思路:每一个房间期望都是可加的。参考
单独考虑一个房间,假设有k个房间被炸开都会导致这个房间被打开。
那么炸一次这个房间被打开的概率即为kn。也就意味着为了把这个房间打开的期望炸的次数为nk。所有加起来后除以n就可以。bitset优化。
bitset<N>b[N];
int cnt[N];
int main(){
int T;sf("%d",&T);
int cas=0;
int n;
while(T--){
sf("%d",&n);
rep(i,0,n-1)b[i].reset(),cnt[i]=0,b[i][i]=1;
rep(i,0,n-1){
int x;sf("%d",&x);
while(x--){
int t;sf("%d",&t);
b[i][t-1]=1;
}
}
mem(cnt,0);
rep(i,0,n-1)
rep(j,0,n-1)
if(b[j][i])
b[j]|=b[i];
rep(i,0,n-1)
rep(j,0,n-1)
if(b[i][j])cnt[j]++;
double ans=0;
rep(i,0,n-1)ans+=1.0/cnt[i];
pf("Case #%d: %.5lf\n",++cas,ans);
}
}
—————————————————————————————————————
参考http://blog.csdn.net/sin_xf/article/details/47080125
题意:给n个点m条边,问最多可以添加几条边使图为完全二分图
分析:如果二分图没有限制,看到是两边分别为n/2个点和n-n/2个点的最优但是可 能出现大于此点的情况,比如n=4,m=3,边为1 2,1 3,1 4.此时完全二分图边最多为3,所以要求得二分图左边或者右边可达到的离n/2最近的点数是多少为最优解,于是采用染色分别求出各个联通快的2种颜色的各个点数,然后用推出能达到的点数,这里dp[i]的下一个状态是dp[i+1]+d[i+1][0]和dp[i+1][1](dp[i]为前i个二分图的能达到的最大点数
),直接做n*n的复杂度,于是采用bitset优化,复杂度降为n,然后在结果中选取最优
感悟:
这个地方的bitset对于dp 的优化很大。。。
int n,m;
int e,fst[N],nxt[N<<1],vv[N<<1];
int col[N];
bitset<10010>dp;
void add(int u,int v){
nxt[e]=fst[u];vv[e]=v;fst[u]=e++;
}
int a1,a2;
void dfs(int u,int val){
col[u]=1;
if(val==1)a1++;
else a2++;
for(int i=fst[u];~i;i=nxt[i]){
int v=vv[i];
if(!col[v])dfs(v,val^1);
}
}
int a[N],b[N];
int main(){
int T;sf("%d",&T);
while(T--){
mem(fst,-1);mem(col,0);e=0;
sf("%d%d",&n,&m);
rep(i,1,m){ int u,v;sf("%d%d",&u,&v);add(u,v);add(v,u); }
int cnt=0;
for(int i=1;i<=n;++i){
if(!col[i]){
++cnt;a1=0,a2=0;
dfs(i,1);
a[cnt]=a1;b[cnt]=a2;
//bug
}
}
dp.reset(); dp[0]=1;
for(int i=1;i<=cnt;++i){
dp=(dp<<a[i])|(dp<<b[i]);
}
int ans=0;
for(int i=1;i<n;++i){
if(dp[i])ans=max(ans,i*(n-i)-m);
}
pf("%d\n",ans);
}
}
题目大意:给定两个n阶矩阵,求矩阵相乘后模3.
解题思路:因为矩阵模掉3后只有0,1,2三种情况。所以对于矩阵A,记录每一行中1,2的位置,借助bitset。矩阵B中每一列1,2的位置。然后对于结果中每个位置,只要考虑1∗1,1∗2,2∗1,2∗2的个数即可。
感悟:
这个地方的&用的很好。。。
参考http://blog.csdn.net/keshuai19940722/article/details/38391913
int n;
bitset<N>x[N][2],y[N][2];
int solve(int xx,int yy){
int ret=0;
for(int i=0;i<2;++i){
for(int j=0;j<2;++j){
bitset<N>k;k=x[xx][i]&y[yy][j];
ret=(ret+(i+1)*(j+1)*k.count())%3;
}
}
return ret;
}
int main(){
while(~sf("%d",&n)){
for(int i=0;i<n;++i){
for(int j=0;j<2;++j)
x[i][j].reset(),y[i][j].reset();
}
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
int a;sf("%d",&a);a%=3;
if(a)x[i][a-1].set(j,1);
}
}
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
int a;sf("%d",&a);a%=3;
if(a)y[j][a-1].set(i,1);
}
}
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
pf("%d%c",solve(i,j),j==n-1?'\n':' ');
}
}
}
}
参考http://blog.csdn.net/stay_accept/article/details/71167905
题意:给出n个集合(n<=1000),每个集合中最多有10000个数,每个数的范围为1~10000,给出q次询问(q<=200000),每次给出两个数u,v判断是否有一个集合中同时含有u,v两个数
分析:一开始觉得10的8次方刚刚好。。。看了题解才知道不需要这样。。
int n;
bitset<1010>bi[N];
int main(){
while(~sf("%d",&n)){
rep(i,1,10000)bi[i].reset();
rep(i,1,n){
int x;sf("%d",&x);
while(x--){
int u;sf("%d",&u);
bi[u].set(i-1,1);
}
}
int q;sf("%d",&q);
while(q--){
int u,v;sf("%d%d",&u,&v);
bitset<1010>k;k=bi[u]&bi[v];
if(k.count()!=0)puts("Yes");
else puts("No");
}
}
}