「暑期訓練」「Brute Force」 Bitonix' Patrol (CFR134D1D)

SamHX發表於2018-08-10

題意

n個站點,排成圓形,每站間距m,現從0點出發,提供t個油箱,問:拿走若干個油箱可以讓出發者無法到達任意一個站點,這樣的方案有多少?(出發者可以順時針走,也可以逆時針走)資料規模分別為:2n1000,1m120,1t10000

分析

本題想了好幾天,看了若干個題解:

一併表示謝意。

首先要注意到幾個個有趣的事實:對於一個容量vi的油箱,它的作用與vi%m等效。因為題目並不要求你到達第幾個站點,它只想你達不到;另外,每個容量只能帶一個,不然出發者顯然可以原路返回;而類似地,vimvi等效。
因此,題目的規模輕易的可以降到260。這樣就可以考慮狀態壓縮了。設狀態儲存在b(bitset)中,記bi為真時,油量為i的油箱不可以使用(最後的解利用乘法原理計算)。那麼,第j個被使用時,b轉化為b|b>>>k|b<<<k(即迴圈左移/迴圈右移)。簡單說下為什麼要右移:若原來第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;
}

相關文章