因为只有std,没有自我实现,所以是无码专区
主要是为了训练思维能力
solution才是dls正解,但是因为只有潦草几句,所以大部分会有我自己基于正解上面的算法实现过程,可能选择的算法跟std中dls的实现不太一样。
std可能也会带有博主自己的注释。
problem
把 nnn 个球放入 nnn 个盒子里面,每个盒子里恰好都有一个球,标号从 111 开始。
且盒子标号和里面装的球的标号的因子个数必须相同。
答案对 500009500009500009 取模。多组数据。
T≤1e5,n≤1e9T\le 1e5,n\le 1e9T≤1e5,n≤1e9。
我的想法
observation
:因子数不同的之间互相独立,因子数相同的之间方案数为阶乘,所以实际上是不同因子数的方案数的乘积。
对于 70%70\%70% 的 n≤1e6n\le 1e6n≤1e6 数据,可以线性筛预处理将所有数按照因子个数分类,然后计算即可。
多组数据肯定不能每次都 O(n)O(n)O(n) 的扫一遍。
将查询的 nin_ini 按升序排列,指针扫的时候将 iii 加入,就单独处理 iii 因子个数那个集合的贡献,很好维护。
observation
:111 只能放在 111 里。
observation
:质数之间可以互相放。
由整数的唯一标准分解,所有数都可以被若干个质数的幂表示。
solution
观察到,模数是非常小的,不同于往常的大质数。
所以当 cntx≥modcnt_x\ge modcntx≥mod 之后,答案一定为 000。
cntx:cnt_x:cntx: 因子数为 xxx 的个数。
最后答案为 ∏cntx!\prod cnt_x!∏cntx! 。
通过打表发现,当 n≥2250000n\ge 2250000n≥2250000,就已经存在一个 cntx≥modcnt_x\ge modcntx≥mod 了。
所以只需要在 n<2250000n<2250000n<2250000 时用线性筛求出每个数的因子数,乘上对应的 cntxcnt_xcntx,当 n≥2250000n\ge 2250000n≥2250000 直接输出 000 即可。
一般而言,当模数不是寻常的模数时,正解往往会隐藏在模数的性质背后。
当模数是常见的大质数,一般都是数学计算方案了。
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;elsendivisors[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;elsendivisors[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);}
}