链接
题意:
给定
n
n
n 个魔豆和二维目的地
(
x
,
y
)
(x,y)
(x,y),每颗魔豆有两个属性
(
a
,
b
)
(a,b)
(a,b),如果在点
(
x
1
,
y
1
)
(x1,y1)
(x1,y1) 吃下这颗魔豆就会从移动到
(
x
1
+
a
,
y
1
+
b
)
(x1+a,y1+b)
(x1+a,y1+b) ,从
(
0
,
0
)
(0,0)
(0,0) 开始,有多少种方案可以到达
(
x
,
y
)
(x,y)
(x,y),魔豆可以任意选取,相同的魔豆不同排列也被视为不同方案
(
1
<
=
n
<
=
32
,
−
1
0
9
<
=
d
x
,
d
y
<
=
1
0
9
,
−
1
0
9
<
=
a
i
,
b
i
<
=
1
0
9
)
(1 <= n <=32, -10^{9}<= dx,dy <= 10^{9},-10^{9}<= ai,bi <= 10^{9})
(1<=n<=32,−109<=dx,dy<=109,−109<=ai,bi<=109)
分析:
n
n
n 特别小,我们尝试把它二分成两部分
n
1
n_1
n1 和
n
2
n_2
n2,每部分统计所有的选择,排序,去重,这样量级上限是
2
16
2^{16}
216 ,完全可以接受,然后枚举第二个部分的点,从第一部分里二分查找是否有可以到达终点的方案就可以了
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD = 1e9+7;
int n,m;
ll ex,ey,fac[40];
struct node{
ll x,y,cnt,time;
bool operator == (const node& a)const{
return a.x==x&&a.y==y&&a.cnt==cnt;
}
}e1[20],e2[20],a[1<<17],b[1<<17],A[1<<17],B[1<<17];
int cnta,cntb,cntA,cntB;
bool cmp(node a,node b)
{
if(a.x==b.x&&a.y==b.y) return a.cnt<b.cnt;
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
void init(int m,node s[],int &cnts,node S[],int &cntS,node e[])
{
for(int i=0;i<(1<<m);i++)
{
ll x=0,y=0,cnt=0;
for(int k=0;k<m;k++)
if((1<<k)&i)
x+=e[k].x,y+=e[k].y,cnt++;
s[cnts++]=(node){x,y,cnt,1};
}
sort(s,s+cnts,cmp);
for(int i=0;i<cnts;i++)
{
int tim=1;
while(i+1<cnts&&s[i]==s[i+1]) i++,tim++;
S[cntS]=s[i];
S[cntS++].time=tim;
}
}
int main()
{
fac[1]=1; for(int i=2;i<=32;i++) fac[i]=fac[i-1]*i%MOD;
int T; cin>>T;
while(T--)
{
cnta=cntb=cntA=cntB=0;
cin>>n>>ex>>ey;
m=n/2;
for(int i=0;i<m;i++) cin>>e1[i].x>>e1[i].y;
for(int i=0;i<n-m;i++) cin>>e2[i].x>>e2[i].y;
init(m,a,cnta,A,cntA,e1);
init(n-m,b,cntb,B,cntB,e2);
ll ans=0;
for(int i=0;i<cntB;i++)
{
node res;
res.x=ex-B[i].x,res.y=ey-B[i].y;
int l=0,r=cntA-1,mid=l,flag=0;
while(l<=r)
{
mid=(l+r)>>1;
if(A[mid].x==res.x&&A[mid].y==res.y){flag=1;break;}
if(res.x<A[mid].x|| res.x==A[mid].x&&res.y<A[mid].y) r=mid-1;
else l=mid+1;
}
if(!flag) continue;
ans+=fac[A[mid].cnt+B[i].cnt]*A[mid].time%MOD*B[i].time%MOD;
ans%=MOD;
l=mid-1,r=mid+1;
while(l>=0&&A[l].x==res.x&&A[l].y==res.y){
ans+=fac[A[l].cnt+B[i].cnt]*A[l].time%MOD*B[i].time%MOD;
ans%=MOD;
l--;
}
while(r<cntA&&A[r].x==res.x&&A[r].y==res.y){
ans+=fac[A[r].cnt+B[i].cnt]*A[r].time%MOD*B[i].time%MOD;
ans%=MOD;
r++;
}
}
cout<<ans<<endl;
}
}