NOIP 模拟26
T1:
n:1e14,于是对于题目中两个式子,考虑避开n
很容易发现关键点在于a+b|a*b,对于如此简洁的数学式
考虑其数学本质,对该式进行唯一分解考虑。
这里考虑最大公约数的唯一分解表示:即两数的极
大公共质因子集之积,发现设(a,b)=d,a'=a/d,b'=b/d
则d即为两数的极大公共质因子集之积,且(a',b')=1
于是原式转化为a'+b'|d*a'*b',数论视角下发现若(a,b)=1
则a+b∤a*b于是发现使得原式成立的条件为a'+b'|d
将所得式带入a+b<=n -> (a'+b')*d<=n -> k*(a'+b')^2<=n
-> a'+b'<=√n -> d<=n/(a'+b')^2于是原问题转化为求存在多少
(a,b,d)对,其中d<=n/(a'+b') , a'+b'<=√n
观察发现2式只有一个变量(a'+b')而1式存在两个变量且
与2式相关于是考虑满足2式的(a'+b')存在多少对,由于
(a',b')=1,限制条件不足无法计算,考虑增加限制条件:设
a'+b'=k,于是可得(a',k-a')=1 -> (a',k)=1,于是发现满足条件的
(a',b')对的个数极为phi(k),求解√n内phi(k)并求出对应d,
乘法原理即可
代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define I int 4 #define LL long long 5 #define B bool 6 const I MAXN = 1e7 + 3; 7 I tmp,cnt,prime[MAXN],euler[MAXN]; 8 LL n,res; 9 B notprime[MAXN]; 10 signed main () { 11 cin >> n; 12 tmp = sqrt (n); 13 for (I i(2);i <= tmp; ++ i) { 14 if (!notprime[i]) 15 prime[++cnt] = i, euler[i] = i - 1; 16 for (I j(1);j <= cnt && i * prime[j] <= tmp; ++ j) { 17 notprime[i * prime[j]] = 1; 18 if (i % prime[j] == 0) { euler[i * prime[j]] = euler[i] * prime[j]; break; } 19 euler[i * prime[j]] = euler[i] * (prime[j] - 1); 20 } 21 res += n / (1ll * i * i) * euler[i]; 22 } 23 cout << res << endl; 24 }
T2:
LIS板子,问题一线段树,树状数组维护皆可,问题二同样,
树状数组或线段树维护LIS长度与问题一操作相同
问题二另一种解法:发现问题本质为求LIS长度的个数,发现
对于LIS相同,其R值必定递减,于是采用双指针(R单调递减)即可
代码如下(双指针):
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define I int 4 #define LL long long 5 #define V void 6 #define C char 7 #define B bool 8 const I MAXN = 1e5 + 7; 9 const I mod = 123456789; 10 I n,typ,upd,res,tmp,maxn,num; 11 I R[MAXN],f[MAXN],g[MAXN]; 12 vector <I> sta[MAXN],pre[MAXN]; 13 struct TEL { 14 #define lowbit(x) (x & -x) 15 I c[MAXN]; 16 inline V insert (I x,I y) { for ( ;x <= upd;x += lowbit(x)) c[x] = max (c[x],y); } 17 inline I secque (I x) { 18 I res(INT_MIN); 19 for ( ; x ;x -= lowbit(x)) res = max (res,c[x]); 20 return res; 21 } 22 }TEL; 23 signed main () { 24 cin >> n >> typ; 25 for (I i(1);i <= n; ++ i) 26 cin >> R[i], upd = max (upd,++R[i]); 27 for (I i(1);i <= n; ++ i) { 28 tmp = TEL.secque (R[i] - 1) + 1; 29 TEL.insert (R[i],tmp); 30 f[i] = tmp; maxn = max (maxn,tmp); 31 } 32 cout << maxn << endl; 33 if (typ) { 34 for (I i(0);i <= maxn; ++ i) sta[i].push_back(1),pre[i].push_back(0); 35 sta[0].push_back (INT_MIN); pre[0].push_back(1); 36 for (I i(1);i <= n; ++ i) { 37 while (sta[f[i] - 1][0] < sta[f[i] - 1].size () && R[sta[f[i] - 1][sta[f[i] - 1][0]]] >= R[i]) sta[f[i] - 1][0] ++ ; 38 g[i] = pre[f[i] - 1][pre[f[i] - 1].size() - 1] - pre[f[i] - 1][sta[f[i] - 1][0] - 1]; 39 sta[f[i]].push_back(i); 40 pre[f[i]].push_back((pre[f[i]][pre[f[i]].size() - 1] + g[i]) % mod); 41 if (!(f[i]^maxn)) (num += g[i]) %= mod; 42 } 43 cout << (num + mod) % mod << endl; 44 } 45 }
T3:
fib的显著特征为子结构性,即其差分序列仍为fib,拓展到树上
子树的结构完全相同,此时考虑DP思想,将问题转化到子结构上
注意的是,通常题目并不一定给出完全序列,即可能存在变形
此时为了简化问题,我们可以考虑根据题目构造相似数列来更好贴合
题目,对于此题,观察发现可以构造1,0,1,1,2,3。。。数列
观察fib树,枚举深度确定贡献与子树数量利用fib规律计算
代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define I int 4 #define LL long long 5 const I MAXN = 5e3 + 3; 6 const I mod = 123456789; 7 I n; 8 LL fib[MAXN],sum[MAXN],res[MAXN << 1]; 9 signed main () { 10 cin >> n; 11 fib[1] = fib[3] = sum[1] = sum[2] = 1; sum[3] = 2; 12 for (I i(4);i <= n; ++ i) 13 fib[i] = (fib[i - 1] + fib[i - 2]) % mod,sum[i] = (sum[i - 1] + fib[i]) % mod; 14 for (I i(2);i < n; ++ i) res[i] = sum[n - i] * fib[i + 1] % mod; 15 for (I i(1);i <= n; ++ i) 16 for (I j(1);j <= n; ++ j) 17 (res[i + j] += (sum[n - max(i,j) + 1] - 1) * fib[j + 1] % mod * fib[i]) %= mod; 18 for (I i(1);i <= n << 1; ++ i) cout << res[i] << ' '; 19 }

浙公网安备 33010602011771号