因为只有std,没有自我实现,所以是无码专区
主要是为了训练思维能力
solution才是dls正解,但是因为只有潦草几句,所以大部分会有我自己基于正解上面的算法实现过程,可能选择的算法跟std中dls的实现不太一样。
std可能也会带有博主自己的注释。
problem
把 n n n 个球放入 n n n 个盒子里面,每个盒子里恰好都有一个球,标号从 1 1 1 开始。
且盒子标号和里面装的球的标号的因子个数必须相同。
答案对 500009 500009 500009 取模。多组数据。
T ≤ 1 e 5 , n ≤ 1 e 9 T\le 1e5,n\le 1e9 T≤1e5,n≤1e9。
我的想法
observation
:因子数不同的之间互相独立,因子数相同的之间方案数为阶乘,所以实际上是不同因子数的方案数的乘积。
对于 70 % 70\% 70% 的 n ≤ 1 e 6 n\le 1e6 n≤1e6 数据,可以线性筛预处理将所有数按照因子个数分类,然后计算即可。
多组数据肯定不能每次都 O ( n ) O(n) O(n) 的扫一遍。
将查询的 n i n_i ni 按升序排列,指针扫的时候将 i i i 加入,就单独处理 i i i 因子个数那个集合的贡献,很好维护。
observation
:
1
1
1 只能放在
1
1
1 里。
observation
:质数之间可以互相放。
由整数的唯一标准分解,所有数都可以被若干个质数的幂表示。
solution
观察到,模数是非常小的,不同于往常的大质数。
所以当 c n t x ≥ m o d cnt_x\ge mod cntx≥mod 之后,答案一定为 0 0 0。
c n t x : cnt_x: cntx: 因子数为 x x x 的个数。
最后答案为 ∏ c n t x ! \prod cnt_x! ∏cntx! 。
通过打表发现,当 n ≥ 2250000 n\ge 2250000 n≥2250000,就已经存在一个 c n t x ≥ m o d cnt_x\ge mod cntx≥mod 了。
所以只需要在 n < 2250000 n<2250000 n<2250000 时用线性筛求出每个数的因子数,乘上对应的 c n t x cnt_x cntx,当 n ≥ 2250000 n\ge 2250000 n≥2250000 直接输出 0 0 0 即可。
一般而言,当模数不是寻常的模数时,正解往往会隐藏在模数的性质背后。
当模数是常见的大质数,一般都是数学计算方案了。
std
#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include <cassert>
#include <ctime>
#include <queue>
using namespace std;
#define VAR(a,b) __typeof(b) a=(b)
#define REP(i,n) for(int _n=n, i=0;i<_n;++i)
#define FOR(i,a,b) for(int i=(a),_b=(b);i<=_b;++i)
#define FORD(i,a,b) for(int i=(a),_b=(b);i>=_b;--i)
#define FOREACH(it,c) for(VAR(it,(c).begin());it!=(c).end();++it)
#define ALL(c) (c).begin(),(c).end()
#define TRACE(x) cerr << "TRACE(" #x ")" << endl;
#define DEBUG(x) cerr << #x << " = " << x << endl;
typedef long long LL;
typedef unsigned long long ULL;
const int INF = 1000000000;
const LL INFLL = LL(INF) * LL(INF);
template<class T> inline int size(const T &c) {
return c.size();
}
int rint() {
int x;
if (scanf("%d", &x) != 1)
return -1;
return x;
}
LL rLL() {
LL x;
if (scanf("%lld", &x) != 1)
return -1;
return x;
}
const int MOD = 500009;
const int MAXN = 2250000;
int main() {
freopen("ball.in", "r", stdin);
freopen("ball.out", "w", stdout);
vector<int> ndivisors(MAXN + 1, 1);
int p = 2;
for (p = 2; p * p * p <= MAXN; ++p)
if (ndivisors[p] == 1) {
int pk = p;
for (int k = 1;; ++k) {
int mm = 0;
for (int q = pk; q <= MAXN; q += pk) {
++mm;
if (mm == p)
mm = 0;
else
ndivisors[q] *= k + 1;
}
LL pk2 = LL(pk) * p;
if (pk2 > MAXN)
break;
pk = int(pk2);
}
}
for (; p * p <= MAXN; ++p)
if (ndivisors[p] == 1) {
int pk = p;
for (int k = 1; k <= 2; ++k) {
int mm = 0;
for (int q = pk; q <= MAXN; q += pk) {
++mm;
if (mm == p)
mm = 0;
else
ndivisors[q] *= k + 1;
}
pk *= p;
}
}
for (; p <= MAXN; ++p)
if (ndivisors[p] == 1) {
for (int q = p; q <= MAXN; q += p) {
ndivisors[q] *= 2;
}
}
vector<unsigned> cnt(MAXN + 1, 0);
vector<unsigned> res(MAXN + 1, 0);
res[0] = 1;
for (int n = 1; n <= MAXN; ++n) {
int d = ndivisors[n];
++cnt[d];
res[n] = res[n - 1] * (cnt[d] % 1024u) % unsigned(MOD);
if (cnt[d] >= 1024u) {
unsigned a = res[n - 1] * (cnt[d] >> 10) % unsigned(MOD);
res[n] = (res[n] + (a << 10)) % unsigned(MOD);
}
if (res[n] == 0)
break;
}
int ntc = rint();
REP(tc, ntc) {
int n = rint();
int r = n <= MAXN ? res[n] : 0;
printf("%d\n", r);
}
}