「暑期训练」「Brute Force」 Bitonix' Patrol (CFR134D1D)
题意
有个站点,排成圆形,每站间距,现从0点出发,提供个油箱,问:拿走若干个油箱可以让出发者无法到达任意一个站点,这样的方案有多少?(出发者可以顺时针走,也可以逆时针走)数据规模分别为:
分析
本题想了好几天,看了若干个题解:
- 许昊然julao的codeforces解题报告
- https://blog.csdn.net/V5ZSQ/article/details/78949105
- 一份AC代码,不知道哪个julao写的
一并表示谢意。
首先要注意到几个个有趣的事实:对于一个容量的油箱,它的作用与等效。因为题目并不要求你到达第几个站点,它只想你达不到;另外,每个容量只能带一个,不然出发者显然可以原路返回;而类似地,同等效。
因此,题目的规模轻易的可以降到。这样就可以考虑状态压缩了。设状态保存在b(bitset)中,记为真时,油量为i的油箱不可以使用(最后的解利用乘法原理计算)。那么,第j个被使用时,b转化为(即循环左移/循环右移)。简单说下为什么要右移:若原来第i个状态真,那么说明变为i时可以到达。那么现在必须让他达不到油箱容量i+k,才能使得出发者仍旧不能到达。
最终题目得解。
代码
#include <bits/stdc++.h>
#define MP make_pair
#define PB push_back
#define fi first
#define se second
#define ZERO(x) memset((x), 0, sizeof(x))
#define ALL(x) (x).begin(),(x).end()
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define per(i, a, b) for (int i = (a); i >= (b); --i)
#define QUICKIO \
ios::sync_with_stdio(false); \
cin.tie(0); \
cout.tie(0);
using namespace std;
using ll = long long;
using ull = unsigned long long;
using pi = pair<int, int>;
using pii = pair<int, pi>;
const int MAXN=125;
using bst = bitset<MAXN>;
#define NDEBUG
template<typename T>
T read()
{
T tmp; cin>>tmp;
return tmp;
}
ll ans=0,mod=1000000007;
int n,m,k;
int cnt[MAXN];
inline bst mv(bst& x,int val,bool opt,int sz=m)
{
if(opt) // left
{
return (x<<val)|(x>>(sz-val));
}
else // right
{
return (x>>val)|(x<<(sz-val));
}
}
void dfs(bst nb,int n,ll mulv)
{
ans=(ans+mulv)%mod;
rep(i,n,m/2)
{
if(cnt[i] && !nb[i] && !nb[m-i])
{
dfs(nb|mv(nb,i,true)|mv(nb,i,false),i+1,mulv*cnt[i]%mod);
}
}
}
int main()
{
QUICKIO
//cin>>n>>m>>k;
scanf("%d%d%d",&n,&m,&k);
ZERO(cnt);
rep(i,0,k-1)
{
//int tmp=read<int>()%m;
int tmp; scanf("%d",&tmp);
tmp%=m;
cnt[min(tmp,m-tmp)]++;
}
bst tmp=1;
dfs(tmp,0,1);
printf("%d\n",int(ans%mod));
//cout<<ans<<endl;
return 0;
}
如非注明,原创内容遵循GFDLv1.3发布;其中的代码遵循GPLv3发布。