題意
有個站點,排成圓形,每站間距,現從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;
}