Easy to think but hard to write.
Solution #
Since the radius of a circle is at most 5, we only need to check the status of 10 blocks before it, which could be represented as a binary number. Let be the number of ways to draw circles whose right boundary is , with mask of . Here if the k-th bit of the mask is 1, it means that you can put a circle whose left boundary is .
For a fixed right boundary, there are 5 possible positions for center, so circle combinations. So our strategy is that for each position, we check masks and circle combinations, then transition if possible.
In order to make coding easier, we could calculate some helper array: le
is the mask for the left boundary of the corresponding center mask, all the bits in mhi[i]
to the right of the highest bit of le[i]
is set to 1 to make positions inside the circle unavailable for the next position.
Code #
#include <bits/stdc++.h>
#define all(x) (x).begin(),(x).end()
#define sz(x) int(x.size())
using namespace std;
using ll = long long;
using pii = pair<int, int>;
template<typename... T> void rd(T&... args) {((cin>>args), ...);}
template<typename... T> void wr(T... args) {((cout<<args<<" "), ...);cout<<endl;}
constexpr int mod=1e9+7;
ll dp[1010][1<<10];
int already[1010];
int le[32], mhi[32];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, k;
cin>>n>>k;
for (int i=0; i<k; i++) {
int c, r;
cin>>c>>r;
already[c+r]|=(1<<(r-1));
}
for (int i=0; i<32; i++) {
for (int j=0; j<5; j++) {
if (i>>j&1) {
le[i]|=(1<<(2*j+1));
mhi[i]=(1<<(2*j+1))-1;
}
}
}
dp[0][0]=1;
for (int i=0; i<=n; i++) {
for (int mask=0; mask<1024; mask++) {
if (!dp[i][mask]) continue;
for (int k=0; k<32; k++) {
if ((already[i]&k) != already[i]) continue;
if ((mask & le[k]) != le[k]) continue;
int nxt=mask-(mask & mhi[k]);
nxt=(2*nxt+1)&1023;
(dp[i+1][nxt]+=dp[i][mask])%=mod;
}
}
}
ll ans=0;
for (int i=0; i<1024; i++) (ans+=dp[n+1][i])%=mod;
cout<<ans;
return 0;
}