注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

时光机TimeMachine

——一个退役OIer

 
 
 

日志

 
 

[BZOJ2451][Ural1695] Work for Robots  

2015-07-12 15:42:28|  分类: Problems |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

2451: Ural1695 Work for Robots

随便找道题做
题解在代码下方

#include<cstdio>
#include<map>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
int n,m,bh[200];
ll two[200];
int scan(){int i=0;scanf("%d",&i);return i;}
map<ll,ll>F,G;
int rand(int l,int r){return rand()%(r-l+1)+l;}
ll f(ll S){
//printf("%d\n",S);
if(S==0)return 1;
if(F.count(S))return F[S];
ll re1,re2,s1,s2;
re1 = 1;re2 = 0;s2=S;
for(int i=0;two[i]<=S;i++)
if(two[i]&S){
s1 = G[two[i]] & S;
if(s1 == (S^two[i]))
s2 ^= two[i],re1*=2;
else if(s1 == 0)
s2 ^= two[i],re2++;
}
if(s2 == 0){
re1 += re2;
F[S] = re1;
return re1;
}
s1 = s2&-s2;
re1 = re1*(f(G[s1]&s2) + f(s2-s1)) + re2;
F[S] = re1;
return re1;
}
int main(){
int i,j;
srand(555);
//freopen("in.txt","r",stdin);
n=scan();
for(i=two[0]=1;i<=60;i++)two[i] = two[i-1]*2;
for(i=0;i<n;i++)bh[i]=i;
for(i=0;i<n;i++)swap(bh[i],bh[rand(0,n-1)]);
for(i=0;i<n;i++){
ll e=0;
for(j=0;j<n;j++){
char cc;scanf(" %c",&cc);
if(cc=='1')e |= two[bh[j]];
}
/*if(two[bh[i]] == 1)
two[bh[i]] = 1;*/
G[two[bh[i]]] = e;
}
ll ans = f(two[n]-1);
cout << ans << endl;
return 0;
}

题解:
记忆化爆搜+剪枝+随机化
设f(S)为S状态的方案数,G(x)为x的出边的集合
那么我们令x = S&-S
f(S) = f(S&G(x)) + f(S-x)
一些优化:
1.把编号打乱
2.对于f(S)找出元素x∈S且 (G[x]&(S-x)) = (S-x),那么这个元素选不选都可以,直接S-=x后把最后答案*2
3.对于f(S)找出元素x∈S且 (G[x]&(S-x)) = 0,那么这个元素只能自己一个团,S-=x后把最后答案+1
  评论这张
 
阅读(142)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017