Description
给出
n
个整数
Input
第一行一整数
n
,之后输入
Output
输出满足条件的排列的个数,结果模 109+7
Sample Input
3
2 3 5
2
5 7
Sample Output
1
Solution
k=0 时答案显然为 n!
k=1
时,问题转化为求
{a1,...,an}
的非空子集个数使得其和为
b1
,由于
n
只有
k=2
时,假设
b1<b2
(
b1=b2
对应
k=1
的情况),那么不合法排列数即为:和为
b1
的非空子集个数
+
和为
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
#include<unordered_map>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
typedef pair<P,P>PP;
const int INF=0x3f3f3f3f,maxn=25;
#define mod 1000000007
int n,a[maxn],k,b1,b2,f[maxn];
map<P,int>m1,m2;
map<PP,int>M1,M2;
void Solve1(int *a,int n,map<P,int>&m,int b)
{
int N=1<<n;
for(int i=0;i<N;i++)
{
int num=0,sum=0;
for(int j=0;j<n;j++)
if(i&(1<<j))num++,sum+=a[j];
if(sum>b)continue;
m[P(sum,num)]++;
}
}
void Solve2(int *a,int n,map<PP,int>&M)
{
int g[maxn],res;
int N=1;
for(int i=1;i<=n;i++)N*=3;
for(int i=0;i<N;i++)
{
int num1=0,num2=0,sum1=0,sum2=0;
res=0;
int temp=i;
while(temp)g[res++]=temp%3,temp/=3;
for(int j=0;j<res;j++)
if(g[j]==1)num1++,sum1+=a[j];
else if(g[j]==2)num2++,sum2+=a[j];
if(sum1>b1||sum2>b2)continue;
M[PP(P(sum1,num1),P(sum2,num2))]++;
}
}
int Deal(int b)
{
int ans=0;
m1.clear(),m2.clear();
Solve1(a+1,n/2,m1,b);
Solve1(a+n/2+1,n-n/2,m2,b);
for(auto it=m1.begin();it!=m1.end();it++)
{
P n1=it->first;
if(n1.first>b)continue;
int cnt1=n1.second,num1=it->second;
for(int cnt2=0;cnt2<=n-n/2;cnt2++)
{
P n2=P(b-n1.first,cnt2);
if(m2.find(n2)!=m2.end())
{
int num2=m2[n2];
ans+=(ll)num1*num2%mod*f[cnt1+cnt2]%mod*f[n-cnt1-cnt2]%mod;
if(ans>=mod)ans-=mod;
}
}
}
return ans;
}
bool cmp(int x,int y)
{
return x>y;
}
int main()
{
f[0]=1;
for(int i=1;i<=24;i++)f[i]=(ll)i*f[i-1]%mod;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
sort(a+1,a+n+1,cmp);
scanf("%d",&k);
int ans=f[n];
if(!k)printf("%d\n",ans);
else if(k==1)
{
scanf("%d",&b1);
ans-=Deal(b1);
if(ans<0)ans+=mod;
printf("%d\n",ans);
}
else
{
scanf("%d%d",&b1,&b2);
if(b1>b2)swap(b1,b2);
ans-=Deal(b1);
if(ans<0)ans+=mod;
if(b1==b2)printf("%d\n",ans);
else
{
ans-=Deal(b2);
if(ans<0)ans+=mod;
b2-=b1;
Solve2(a+1,n/2,M1);
Solve2(a+n/2+1,n-n/2,M2);
for(auto it=M1.begin();it!=M1.end();it++)
{
PP t1=it->first;
P n1=t1.first,n2=t1.second;
int sum1=n1.first,sum2=n2.first;
int num1=it->second,cnt1=n1.second,cnt2=n2.second;
for(int cnt3=0;cnt3<=n-n/2;cnt3++)
for(int cnt4=0;cnt3+cnt4<=n-n/2;cnt4++)
{
P n3=P(b1-sum1,cnt3),n4=P(b2-sum2,cnt4);
PP t2=PP(n3,n4);
if(M2.find(t2)!=M2.end())
{
int num2=M2[t2];
ans+=(ll)num1*num2%mod*f[cnt1+cnt3]%mod*f[cnt2+cnt4]%mod*f[n-cnt1-cnt2-cnt3-cnt4]%mod;
if(ans>=mod)ans-=mod;
}
}
}
printf("%d\n",ans);
}
}
return 0;
}