Making Shapes
源码
相当有趣的数位 d p dp dp题。
我们记
c
i
c_i
ci表示第
i
i
i个向量选了多少个。
显然,无论我们如何选择向量,只要我们将所有的向量极角排序,就可以得到这些向量构造的唯一凸多边形,当然需要满足
∑
c
i
(
x
i
,
y
i
)
=
0
\sum c_i(x_i,y_i)=0
∑ci(xi,yi)=0
整个凸包的宽度应该
L
=
∑
c
i
[
x
i
>
0
]
∣
x
i
∣
=
∑
c
i
[
x
i
<
0
]
∣
x
i
∣
L=\sum c_i[x_i>0]|x_i|=\sum c_i[x_i<0]|x_i|
L=∑ci[xi>0]∣xi∣=∑ci[xi<0]∣xi∣,高度同理。
我们需要让这个值小于
m
m
m,且等式两边的值相等。
我们不妨记
A
=
∑
c
i
[
x
i
>
0
]
∣
x
i
∣
,
B
=
∑
c
i
[
x
i
<
0
]
∣
x
i
∣
,
C
=
∑
c
i
[
y
i
>
0
]
∣
y
i
∣
,
D
=
∑
c
i
[
y
i
<
0
]
∣
y
i
∣
A=\sum c_i[x_i>0]|x_i|,B=\sum c_i[x_i<0]|x_i|,C=\sum c_i[y_i>0]|y_i|,D=\sum c_i[y_i<0]|y_i|
A=∑ci[xi>0]∣xi∣,B=∑ci[xi<0]∣xi∣,C=∑ci[yi>0]∣yi∣,D=∑ci[yi<0]∣yi∣。
我们可以将
c
c
c二进制拆分后来统计,这样的话我们就能够一位一位得比较
A
,
B
,
C
,
D
A,B,C,D
A,B,C,D。
由于
A
,
B
,
C
,
D
A,B,C,D
A,B,C,D可能即使只在当前位加,也有可能得到比较大的结果,我们显然不能只存
1
1
1位,得多存几位。
这样一来,如果从高位向低位枚举,每一位就有可能用满
5
5
5位,空间比较大。
我们可以从低位向高位枚举,这样每一位上最多只需要记录
3
(
4
+
4
+
3
+
3
)
2
=
21
\frac{3(4+4+3+3)}{2}=21
23(4+4+3+3)=21了,空间也能承受。
但由于是低位向高位,还需要注意下面的部分是否超过了
m
m
m的低位部分,如果超过了,高位就必须小于
m
m
m的高位了。
记
d
p
i
,
A
,
B
,
C
,
D
,
f
x
,
f
y
dp_{i,A,B,C,D,f_x,f_y}
dpi,A,B,C,D,fx,fy表示
c
c
c的二进制为枚举到了第
i
i
i位,四个值分别为
A
,
B
,
C
,
D
A,B,C,D
A,B,C,D,关于低位超过
m
m
m的情况是
f
x
,
f
y
f_x,f_y
fx,fy。
可以用记忆化搜索更新
d
p
dp
dp值,每一位转移就枚举
c
c
c该位的状态就行了。
时间复杂度 O ( 2 1 4 × 2 2 log m ) O\left(21^4\times 2^2\log\,m\right) O(214×22logm)。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
typedef long double ld;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f;
const int mo=998244353;
const int mod=1e9+7;
const int inv2=5e8+4;
const int jzm=2333;
const int zero=100000;
const int n1=1000;
const int lim=100000000;
const int orG=3,ivG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-6;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*t*a%p;a=1ll*a*a%p;s>>=1;}return t;}
int n,m,dp[35][23][23][23][23][2][2],a[10],b[10];
int sakura(int id,int px,int py,int nx,int ny,bool fx,bool fy){
if(id==30)return px==nx&&py==ny&&(px+fx<=((m>>id)&15))&&(py+fy<=((m>>id)&15));
if(~dp[id][px][py][nx][ny][fx][fy])return dp[id][px][py][nx][ny][fx][fy];
int res=0,up=(m>>id)&1;
for(int i=0;i<(1<<n);i++){
int tpx=px,tpy=py,tnx=nx,tny=ny;bool ffx=fx,ffy=fy;
for(int j=1;j<=n;j++)if((i>>j-1)&1){
if(a[j]>0)tpx+=a[j];else tnx-=a[j];
if(b[j]>0)tpy+=b[j];else tny-=b[j];
}
if((tpx&1)^(tnx&1))continue;if((tpy&1)^(tny&1))continue;
if(up<(tpx&1))ffx=1;if(up>(tpx&1))ffx=0;
if(up<(tpy&1))ffy=1;if(up>(tpy&1))ffy=0;
Add(res,sakura(id+1,tpx>>1,tpy>>1,tnx>>1,tny>>1,ffx,ffy),mo);
}
dp[id][px][py][nx][ny][fx][fy]=res;
return res;
}
signed main(){
read(n);read(m);memset(dp,-1,sizeof(dp));
for(int i=1;i<=n;i++)read(a[i]),read(b[i]);
printf("%d\n",add(sakura(0,0,0,0,0,0,0),mo-1,mo));
return 0;
}