【无码专区6】球与盒子(数学线性筛)
因為只有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);} }總結
以上是生活随笔為你收集整理的【无码专区6】球与盒子(数学线性筛)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 技术情报局(笛卡尔树)
- 下一篇: 怎么查自己的银行卡号 查询银行卡号的方法