SRM 555 div1 MapGuessing(容斥原理)

传送门
考虑枚举每个点作为起点,然后状压序列中的哪些位置可以在初始取任意值。
假设有 k k k个位置,那么这种状态的贡献为 2 k 2^k 2k
但这样同一个状态会被算重。
于是我们考虑容斥来算。
注意剪枝。
代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
typedef long long ll;
const int mogic=1e6+7;
class MapGuessing{
	public:
	struct Hash_table{
		vector<ll>ori[mogic];
		vector<int>tmp;
		inline void clear(){for(ri i=tmp.size()-1;~i;--i)ori[tmp[i]].clear();}
		inline bool query(ll x){
			int t=x%mogic;
			for(ri i=ori[t].size()-1;~i;--i)if(ori[t][i]==x)return 0;
			if(!ori[t].size())tmp.push_back(t);
			return ori[t].push_back(x),1;
		}
	}S;
	vector<ll>sta;
	inline int count(ll x){int ret=0;while(x)x^=x&-x,++ret;return ret;}
	inline ll dfs(int pos,ll all,int coe){
		if(pos==sta.size())return (ll)coe*(1ll<<count(all));
		if(!all)return 0;
		return dfs(pos+1,all,coe)+dfs(pos+1,all&sta[pos],coe!=1?1:-1);
	}
	int val[105];
	inline ll countPatterns(string To,vector<string>Upd){
		string upd;
		S.clear();
		sta.clear();
		int n=To.size();
		for(ri i=0;i<Upd.size();++i)upd=upd+Upd[i];
		ll st,stat;
		int l=0,r=0,t=0;
		for(ri i=0;i<upd.size();++i){
			if(upd[i]=='<')--t;
			if(upd[i]=='>')++t;
			l=min(l,t);
			r=max(r,t);
		}
		if(r-l+1>n)return 0ll;
		for(ri i=-l;i<n-r;++i){
			for(ri j=0;j<n;++j)val[j]=-1;
			st=stat=0;
			char ch;
			bool ff=1;
			for(ri cur=i,j=0,up=upd.size();j<up;++j){
				ch=upd[j];
				switch(ch){
					case '<':--cur;break;
					case '>':++cur;break;
					case '0':val[cur]=0,stat|=1ll<<cur;break;
					case '1':val[cur]=1,stat|=1ll<<cur;break;
				}
				if(cur<0||cur==n){ff=0;break;}
				bool fff=1;
				for(ri j=0;j<n;++j)if(~val[j]&&(val[j]!=(To[j]-'0'))){fff=0;break;}
				if(fff)st=stat;
			}
			if(ff&&S.query(st))sta.push_back(st);
		}
		return sta.size()?dfs(0,(1ll<<n)-1,0):0ll;
	}
};
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值