hihocoder #1456 : Rikka with Lattice(杜教筛)
题意
给你一个\(n*m\)方格图,统计上面有多少个格点三角形,除了三个顶点,不覆盖其他的格点(包括边和内部).
答案对于\(998244353\)取模... (\(n,m \le 5 * 10^9\))
题解
这个题十分的巧妙... 集训时是大佬ztzshiwo出的..
据他所说,是不那么杜教筛的杜教筛QAQ
考试时候提示了一个皮克定理...
皮克定理:
\[S=a+\frac{b}{2}-1
\]\(S\)为格点多边形面积,\(a\)为多边形内部点数,\(b\)为多边形边上点数.
然而我还是只会暴力,正解是真的太神了啊QAQ.
我们考虑一个\(a*b\)的矩形,以它对顶点为端点的三角形,只当\(a \bot b\)时存在四个解.
这个我是听wearry证明的qwq 十分巧妙
简单的证明:
代入皮克定理,可知
当且仅当格点三角形面积为\(S=0+\frac{3}{2}-1=\frac{1}{2}\)时才计入答案
我们可以用叉积的形式表示这个面积. \(S=\frac{1}{2} |AB| |BC| \sin \theta =\frac{1}{2} |\vec {AB} \times \vec{AC}|\).(高中必修内容QAQ)

我们令之前那个矩形的一条对角线为三角形的一条边,
令左下角为向量出发点,也就是其中一个顶点,然后这条边的向量坐标表达就为\((a,b)\).
我们令另外一条边为\((i,j)\),然后三角形面积就是\(\frac{1}{2}|(a,b) \times (i,j)| = \frac{1}{2}|aj - bi|\).
这个为\(\frac{1}{2}\)所以\(|aj-bi|=1\). \(\therefore aj-bi= \pm 1\)
我们是要求解\((i,j)\) 所以不难发现这是一个扩欧的形式,当且仅当\(a \bot b\)时有整数解.
又\(\because 0 < i < a, 0 < j < b\).. \(\therefore\)可以通过扩欧的相邻解确定在这个区域仅一解.
所以\(\pm 1\)各有一解,换个对角线又有对称的一组解.所以最后总共\(2*2=4\)组解.
所以我们要求的就是原图中每个矩形的贡献就行了...
此处\(n\),\(m\)都是要减一的... (至于为啥...手推就知道了QAQ)
\]
\]
\]
令$$\displaystyle S(i)=\sum_{i=1}^{n} i = \frac{n(n+1)}{2}$$.
\]
\]
\]
\]
\]
这个用根号分块就能做到\(\Theta (n+\sqrt {n})\)复杂度啦... 具体推导证明看我的一篇博客线性筛与莫比乌斯反演.
然而这并不能满分...fuck
所以就有杜教筛卡了30分.
\(\displaystyle \sum _{i=1}^{n} \mu(i)\)之前那篇博客杜教筛小结中有介绍.
然后就介绍另外两个套路求的东西吧..
令\(\displaystyle id(x)=x, mx(x)= \mu(i) i\). (然后之后默认把第一个字母大写记作前缀和比如\(\displaystyle Id(x)=\sum_{i=1}^{x} id(i) = \frac{x(x+1)}{2}\))
所以就有
\]
\]
\]
代入之前的套路式子就有
\]
然后就可以尝试推出\(\displaystyle \sum _{i=1}^{n} \mu(i) \cdot i \cdot i\).
这个也不麻烦QAQ...
然后本人比较懒 就直接用c++11 中的unordered_map了(这个基于哈希算法)
有些地方有点细节\(5*10^9 * 5*10^9 = 2.5 * 10^{19}\)会爆long long所以很多地方都要记得先取模!!!
代码
#include <bits/stdc++.h>
#define For(i, l, r) for(register ll i = (l), _end_ = (ll)(r); i <= _end_; ++i)
#define Fordown(i, r, l) for(register ll i = (r), _end_ = (ll)(l); i >= _end_; --i)
#define Set(a, v) memset(a, v, sizeof(a))
using namespace std;
typedef long long ll;
inline ll read() {
ll x = 0, fh = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar() ) if (ch == '-') fh = -1;
for (; isdigit(ch); ch = getchar() ) x = (x<<1) + (x<<3) + (ch ^ '0');
return x * fh;
}
void File() {
#ifdef zjp_shadow
freopen ("1456.in", "r", stdin);
freopen ("1456.out", "w", stdout);
#endif
}
const ll Mod = 998244353;
ll n, m;
const int N = 1e7 + 1e3;
int prime[N], cnt = 0;
int Limit = N - 1e3;
ll mux[N], muxx[N], mu[N];
bitset<N> is_prime;
void Init(int maxn) {
int res;
mu[1] = 1;
is_prime.set(); is_prime[0] = is_prime[1] = false;
For (i, 2, maxn) {
if (is_prime[i]) { prime[++cnt] = i; mu[i] = -1; }
For (j, 1, cnt) {
res = prime[j] * i;
if (res > maxn) break;
is_prime[res] = false;
if (i % prime[j]) mu[res] = -mu[i];
else { mu[res] = 0; break ; }
}
}
For (i, 1, maxn) {
mux[i] = mux[i - 1] + 1ll * mu[i] * i % Mod;
mux[i] = (mux[i] % Mod + Mod) % Mod;
muxx[i] = muxx[i - 1] + 1ll* mu[i] * i % Mod * i % Mod;
muxx[i] = (muxx[i] % Mod + Mod) % Mod;
mu[i] += mu[i - 1];
mu[i] = (mu[i] % Mod + Mod) % Mod;
}
}
ll fpm(ll x, ll power) { ll res = 1; x %= Mod; for (; power; power >>= 1, (x *= x) %= Mod) if (power & 1) (res *= x) %= Mod; return res; }
const ll inv2 = fpm(2, Mod - 2), inv6 = fpm(6, Mod - 2);
ll Sum(ll x) { x %= Mod; return (x + 1) * x % Mod * inv2 % Mod; }
ll sum1, sum2, sum3, sum4;
ll Nextx;
unordered_map<ll, ll> MU, MUX, MUXX;
ll mu_(ll x) {
if (x <= Limit) return mu[x];
if (MU.count(x)) return MU[x];
ll res = 1, Nextx;
For (i, 2, x) { Nextx = x / (x / i); (res += Mod - (Nextx - i + 1) * mu_(x / i) % Mod) %= Mod; i = Nextx; }
return (MU[x] = res);
}
inline ll Sum1(ll x) { x %= Mod; return x * (x + 1) % Mod * inv2 % Mod; }
ll mux_(ll x) {
if (x <= Limit) return mux[x];
if (MUX.count(x)) return MUX[x];
ll res = 1, Nextx;
For (i, 2, x) { Nextx = x / (x / i); (res += Mod - (Sum1(Nextx) - Sum1(i - 1) + Mod) * mux_(x / i) % Mod) %= Mod; i = Nextx; }
return (MUX[x] = res);
}
inline ll Sum2(ll x) { x %= Mod ; return x * (x + 1) % Mod * (2 * x + 1) % Mod * inv6 % Mod; }
ll muxx_(ll x) {
if (x <= Limit) return muxx[x];
if (MUXX.count(x)) return MUXX[x];
ll res = 1, Nextx;
For (i, 2, x) { Nextx = x / (x / i); (res += Mod - (Sum2(Nextx) - Sum2(i - 1) + Mod) * muxx_(x / i) % Mod) %= Mod; i = Nextx; }
return (MUXX[x] = res);
}
int main () {
File();
n = read(); m = read();
if (n > m) swap(n, m);
Init(Limit);
For (x, 1, n) {
Nextx = min(n / (n / x), m / (m / x));
(sum1 += (mu_(Nextx) - mu_(x - 1)) * (n / x) % Mod * (m / x) % Mod * n % Mod * m % Mod) %= Mod;
(sum2 += (mux_(Nextx) - mux_(x - 1)) * Sum(n / x) % Mod * (m / x) % Mod) %= Mod;
(sum3 += (mux_(Nextx) - mux_(x - 1)) * Sum(m / x) % Mod * (n / x) % Mod) %= Mod;
(sum4 += (muxx_(Nextx) - muxx_(x - 1)) * Sum(n / x) % Mod * Sum(m / x) % Mod) %= Mod;
x = Nextx;
}
ll ans = sum1 - 1ll * m * sum2 % Mod - 1ll * n * sum3 % Mod + sum4;
ans = (ans % Mod + Mod) % Mod;
ans = ans * 4ll % Mod;
printf ("%lld\n", ans);
return 0;
}
hihocoder #1456 : Rikka with Lattice(杜教筛)的更多相关文章
- 51nod 1244 莫比乌斯函数之和(杜教筛)
[题目链接] http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1244 [题目大意] 计算莫比乌斯函数的区段和 [题解] 利 ...
- 51nod 1237 最大公约数之和 V3(杜教筛)
[题目链接] https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1237 [题目大意] 求[1,n][1,n]最大公约数之和 ...
- 杜教筛 && bzoj3944 Sum
Description Input 一共T+1行 第1行为数据组数T(T<=10) 第2~T+1行每行一个非负整数N,代表一组询问 Output 一共T行,每行两个用空格分隔的数ans1,ans ...
- 51NOD 1220 约数之和 [杜教筛]
1220 约数之和 题意:求\(\sum_{i=1}^n \sum_{j=1}^n \sigma_1(ij)\) \[ \sigma_0(ij) = \sum_{x\mid i}\sum_{y\mi ...
- BZOJ 4176: Lucas的数论 [杜教筛]
4176: Lucas的数论 题意:求\(\sum_{i=1}^n \sum_{j=1}^n \sigma_0(ij)\) \(n \le 10^9\) 代入\(\sigma_0(nm)=\sum_{ ...
- 51NOD 1222 最小公倍数计数 [莫比乌斯反演 杜教筛]
1222 最小公倍数计数 题意:求有多少数对\((a,b):a<b\)满足\(lcm(a,b) \in [1, n]\) \(n \le 10^{11}\) 卡内存! 枚举\(gcd, \fra ...
- 51NOD 1237 最大公约数之和 V3 [杜教筛]
1237 最大公约数之和 V3 题意:求\(\sum_{i=1}^n\sum_{j=1}^n(i,j)\) 令\(A(n)=\sum_{i=1}^n(n,i) = \sum_{d\mid n}d \c ...
- 【BZOJ4805】欧拉函数求和(杜教筛)
[BZOJ4805]欧拉函数求和(杜教筛) 题面 BZOJ 题解 好久没写过了 正好看见了顺手切一下 令\[S(n)=\sum_{i=1}^n\varphi(i)\] 设存在的某个积性函数\(g(x) ...
- 我也不知道什么是"莫比乌斯反演"和"杜教筛"
我也不知道什么是"莫比乌斯反演"和"杜教筛" Part0 最近一直在搞这些东西 做了将近超过20道题目吧 也算是有感而发 写点东西记录一下自己的感受 如果您真的 ...
随机推荐
- spring,property not found on type
刚开始学spring mvc ,遇到这个报错. jsp页面 user 实体类 public class User { private String name; private int age; pri ...
- cryptojs的使用
项目中经常会遇到加密解密的需求,这里有一个js库非常好用,就是crypto-js.下面记录一下使用方法. 首先,安装js库 npm install crypto-js --save 然后,在项目中使用 ...
- 二叉排序树、平衡二叉树、B树&B+树、红黑树的设计动机、缺陷与应用场景
之前面试时曾被问到"如果实现操作系统的线程调度应该采用什么数据结构?",因为我看过ucore的源码,知道ucore是采用斜堆的方式实现的,可以做到O(n)的插入.O(1)的查找.我 ...
- Maven json包找不到解决办法
在Maven中央仓库找到Maven的jar <dependency> <groupId>net.sf.json-lib</groupId> <artifact ...
- 高可用之KeepAlived(2):keepalived+lvs
*/ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...
- C语言_scanf()和getchar() 使用[粗俗易懂]
原文地址:http://blog.csdn.net/hao5743/article/details/6939661/,以下是我重新整理的以下. 问题描述一:[分析scanf()和getchar()读取 ...
- Docker容器技术
Docker介绍 什么是容器 Linux容器是与系统其他部分隔离开的一系列进程,从另一个系统镜像运行,并由该镜像提供支持进程所需的全部文件. 容器镜像包含了应用的所有依赖项,因而在从开发到测试再到生产 ...
- Java中的自定义数组队列
在Java中,作为所有数据结构中存储和获取速度最快的一种,数组凭借其这种简单易用的优势在各个方面都能大显神威.但是数组也有自身的局限性.数组的长度必须是固定的一旦定义之后就无法动态的更改,这就会造成这 ...
- uploadify上传文件(2)--基础语法
隔了好久,因为最近搬家,离开从小生活的城市,来到杭州.找工作.找房子等诸多事宜耽误了这篇文章许久.今天难得闲暇在旅馆中完成uploadify上传文件系列的第二篇--uploadify使用的基础语法. ...
- gogogo