xjb乱搞题,卡死在无序了。
考虑肯定是枚举个集合划分,然后强制一个集合里的选的b一样嘛,就可以无限背包了,然后发现如果按题意说的无序的话特别难做,不妨考虑有序,即每一个a[i]都有标号,最后除以 ∏ c n t [ a [ i ] ] \prod cnt[a[i]] ∏cnt[a[i]]就好了。
先思考暴力枚举集合划分,系数是什么,系数应该是只和这个集合包含的元素有关的,不妨设 f [ i ] f[i] f[i]表示一个i个点的集合的容斥系数,显然需要满足:
[ n = 1 ] = e f [ x n ] ∗ n ! [n=1]=e^{f}[x^n]*n! [n=1]=ef[xn]∗n!
因为是有标号的。
写成dp式就是 [ n = 1 ] = f [ n ] + ∑ i = 1 n − 1 C n − 1 i − 1 ∗ f [ i ] ∗ [ ( n − i ) = 1 ] [n=1]=f[n]+\sum_{i=1}^{n-1}C_{n-1}^{i-1}*f[i]*[(n-i)=1] [n=1]=f[n]+∑i=1n−1Cn−1i−1∗f[i]∗[(n−i)=1]
归纳一下就是 f [ n ] = ( − 1 ) n − 1 ∗ ( n − 1 ) ! f[n]=(-1)^{n-1}*(n-1)! f[n]=(−1)n−1∗(n−1)!
pty给了生成函数的推法:
要使 e f e^f ef次方的一次项系数为1(常数),>1次项系数为0,那么直接将 l n ( 1 + x ) ln(1+x) ln(1+x)带进去,经过一波求导、泰勒展开可以得到同样的东西。
然后我们肯定不能暴力枚举集合划分。
注意对于一个划分我们只关心每一个集合 ∑ a [ i ] \sum a[i] ∑a[i]和元素个素,那么两种划分的各个集合的 ∑ a [ i ] \sum a[i] ∑a[i]和元素个素一样的是可以缩到一起的,这个可以用set套map实现。
这样直接dp还是会T非的,在搞完上面的之后,再把各个 ∑ a [ i ] \sum a[i] ∑a[i]一样的缩到一起dp,由于30分整数拆分数只有5000+,即可通过本题……
.
.
.
才怪,这个破题卡常到上天,
然后我发现前面的set套map巨慢,所以把set展开成数组,又搞了个hash值来快速比较。
Code:
#include
#define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
#define ff(i, x, y) for(int i = x, B = y; i < B; i ++)
#define fd(i, x, y) for(int i = x, B = y; i >= B; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
const int N = 1e4 + 5;
int n, m, a[N], b[N];
int bz[N], p[N], c[N];
void sieve(int n) {
fo(i, 2, n) {
if(!bz[i]) p[++ p[0]] = i;
for(int j = 1; i * p[j] <= n; j ++) {
bz[i * p[j]] = 1;
if(i % p[j] == 0) break;
}
}
fo(i, 1, p[0]) {
for(ll s = p[i]; s <= n; s *= p[i]) c[i] += n / s;
}
}
const int mo = 1e9 + 7;
ll ksm(ll x, ll y) {
ll s = 1;
for(; y; y /= 2, x = x * x % mo)
if(y & 1) s = s * x % mo;
return s;
}
ll fac[N], nf[N];
struct P {
int x, y;
P(int _x = 0, int _y = 0) { x = _x, y = _y;}
};
bool operator < (P a, P b) {
if(a.x == b.x) return a.y < b.y;
return a.x < b.x;
}
#define ul unsigned long long
struct D {
P a[31];
ul s;
};
ul a3[105];
void calc(D &a) {
a.s = 0;
fo(i, 1, a.a[0].x)
a.s += a3[i] * a.a[i].x + a3[i + 30] * a.a[i].y;
}
bool operator < (D a, D b) {
return a.s < b.s;
if(a.a[0].x != b.a[0].x) return a.a[0].x < b.a[0].x;
if(a.a[1].x != b.a[1].x) return a.a[1].x < b.a[1].x;
if(a.a[2].x != b.a[2].x) return a.a[2].x < b.a[2].x;
fd(j, a.a[0].x, 3) {
if(a.a[j].x < b.a[j].x) return 1;
if(a.a[j].x > b.a[j].x) return 0;
if(a.a[j].y < b.a[j].y) return 1;
if(a.a[j].y > b.a[j].y) return 0;
}
return 0;
}
map<D, int> :: iterator it;
map<D, int> d[2]; int o;
#define fi first
#define se second
map<multiset<int>, int> t;
map<multiset<int>, int> :: iterator it3;
multiset<int> :: iterator it4;
int f[N];
ll ans;
D s;
int main() {
freopen("count.in", "r", stdin);
freopen("count.out", "w", stdout);
a3[0] = 1; fo(i, 1, 100) a3[i] = a3[i - 1] * 7;
scanf("%d %d", &n, &m);
sieve(n);
fo(i, 1, m) scanf("%d", &a[i]);
sort(a + 1, a + m + 1);
int m0 = m; m = 0;
fo(i, 1, m0) {
if(!m || a[i] != a[m])
a[++ m] = a[i], b[m] = 1; else
b[m] ++;
}
fac[0] = 1; fo(i, 1, 30) fac[i] = fac[i - 1] * i % mo;
nf[30] = ksm(fac[30], mo - 2); fd(i, 30, 1) nf[i - 1] = nf[i] * i % mo;
d[o][s] = 1;
fo(i, 1, m) {
fo(tim, 1, b[i]) {
d[!o].clear();
for(it = d[o].begin(); it != d[o].end(); it ++) {
s = (*it).fi;
fo(j, 1, s.a[0].x) {
D g = s;
g.a[j].x += a[i]; g.a[j].y ++;
sort(g.a + 1, g.a + g.a[0].x + 1);
calc(g);
d[!o][g] = (d[!o][g] + (*it).se) % mo;
}
s.a[++ s.a[0].x].x = a[i]; s.a[s.a[0].x].y = 1;
sort(s.a + 1, s.a + s.a[0].x + 1);
calc(s);
d[!o][s] = (d[!o][s] + (*it).se) % mo;
}
o = !o;
// fprintf(stderr, "%d\n", d[o].size());
}
}
for(it = d[o].begin(); it != d[o].end(); it ++) {
s = (*it).fi; ll g = (*it).se;
multiset<int> s2; s2.clear();
fo(i, 1, s.a[0].x) {
s2.insert(s.a[i].x);
g = g * (mo - 1) % mo * fac[s.a[i].y - 1] % mo;
}
t[s2] = (t[s2] + g) % mo;
}
for(it3 = t.begin(); it3 != t.end(); it3 ++) {
memset(f, 0, sizeof f);
f[0] = 1;
multiset<int> s = (*it3).fi;
for(it4 = s.begin(); it4 != s.end(); it4 ++) {
int x = (*it4);
fo(j, x, c[1]) f[j] = (f[j] + f[j - x]) >= mo ? (f[j] + f[j - x] - mo) : (f[j] + f[j - x]);
}
ll sum = 1;
fo(i, 1, p[0]) sum = sum * f[c[i]] % mo;
ans = (ans + sum * (*it3).se) % mo;
}
fo(i, 1, m) ans = ans * nf[b[i]] % mo;
if(m0 & 1) ans = (mo - ans) % mo;
pp("%lld\n", ans);
}