上午
考试 ### 第一题
click
考试的时候这个题的数据比较大,\(n \leq
2e6\)
考虑枚举圆的直径,搞一个双指针来操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include <bits/stdc++.h> #define int long long #define debug using namespace std;const int N = 3e6 +66 ;int n, a[N], sum[N], res;inline int thestars () { scanf ("%lld" ,&n); for (int i = 1 ; i <= n; ++ i) { scanf ("%lld" ,a+i); sum[i] = sum[i - 1 ] + a[i]; } int yhm = sum[n]/2 , num; for (int i = 1 ; i <= n; ++ i) { num = i; if (sum[i] > yhm) break ; } int top = num, kaishi = 0 ; while (kaishi < top || num < n) { while (sum[num] - sum[kaishi] > yhm) ++ kaishi; if (kaishi == top && num == n) break ; if (sum[num] - sum[kaishi] == yhm) ++ res; ++ num; } if (res == 0 || sum[n] % 2 == 1 ) cout<<0 <<"\n" ; else cout << res*(res - 1 )/2 ; return 0 ; } int youngore = thestars ();signed main () {;}
###第二题
click
状态:\(f[i][j][1/0]\) 表示对于\(i\) 到\(j\) 这段区间的作业还没有提交,下一次将提交\(i(0)\) 或\(j(1)\) 处的作业
转移:四个式子,\(f[i][j][0]\) 与\(f[i][j][1]\) 分别可以由左右两边的\(i-1\) 和\(j-1\) 转移,显然:
\(f[i][j][0] = min(f[i][j][0], max(f[i -
1][j][0]+a[i].x-a[i - 1].x, a[i].t))\)
\(f[i][j][0] = min(f[i][j][0], max(f[i][j +
1][1]+a[j + 1].x-a[i].x, a[i].t))\)
\(f[i][j][1] = min(f[i][j][1], max(f[i -
1][j][0]+a[j].x-a[i - 1].x, a[j].t))\)
\(f[i][j][1] = min(f[i][j][1], max(f[i][j +
1][1]+a[j + 1].x-a[j].x, a[j].t))\)
结果:\(min(f[i][i][0],
f[i][i][1])+abs(a[c].x-b)\)
给出AC代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include <bits/stdc++.h> #define LL long long #define debug using namespace std;const int N = 1e5 +66 ;int c, h, b, res = 1 <<30 ;int f[1250 ][1250 ][6 ];struct node {int x, t;}a[N];inline int cmp (node s, node t) {return s.x < t.x;}inline int thestars () { scanf ("%d%d%d" , &c, &h, &b); for (int i = 1 ; i <= c; ++ i) cin >> a[i].x >> a[i].t; sort (a+1 , a+c+1 , cmp); memset (f, 0x7f , sizeof f); f[1 ][c][0 ] = max (a[1 ].x, a[1 ].t), f[1 ][c][1 ] = max (a[c].x, a[c].t); for (int i = 1 ; i <= c; ++ i) { for (int j = c; j >= i; -- j) { f[i][j][0 ] = min (f[i][j][0 ], max (f[i - 1 ][j][0 ]+a[i].x-a[i - 1 ].x, a[i].t)); f[i][j][0 ] = min (f[i][j][0 ], max (f[i][j + 1 ][1 ]+a[j + 1 ].x-a[i].x, a[i].t)); f[i][j][1 ] = min (f[i][j][1 ], max (f[i - 1 ][j][0 ]+a[j].x-a[i - 1 ].x, a[j].t)); f[i][j][1 ] = min (f[i][j][1 ], max (f[i][j + 1 ][1 ]+a[j + 1 ].x-a[j].x, a[j].t)); } } for (int i = 1 ; i <= c; ++ i) res = min (res, min (f[i][i][1 ], f[i][i][0 ])+abs (a[i].x-b)); cout << res; return 0 ; } int youngore = thestars ();signed main () {;}
第三题
恶心程度显然....
给出自己的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 #include <bits/stdc++.h> #define LL long long #define debug using namespace std;const int N = 250 ;int ta, tb, tc;int T;struct node { int x, y; node (){}; node (int X, int Y){x = X, y = Y;} bool operator !=(const node a) const {return x != a.x || y != a.y;} bool operator <(const node a) const {return x == a.x?y<a.y:x<a.x;} }a[N], b[N<<4 ], c[N]; int dx[] = {1 , 1 , 1 , 0 , -1 , -1 , -1 , 0 };int dy[] = {1 , 0 , -1 , -1 , -1 , 0 , 1 , 1 };inline void work () { int i, j; tb = 0 ; for (i = 1 ; i <= ta; ++ i) b[++ tb] = a[i]; for (i = 1 ; i <= ta; ++ i) for (j = 0 ; j < 8 ; ++ j) b[++ tb] = node (a[i].x + dx[j], a[i].y + dy[j]); sort (b + 1 , b + tb + 1 ); j = tb, tb = 1 ; for (i = 2 ; i <= j; ++ i) if (b[i] != b[i - 1 ]) b[++ tb] = b[i]; } inline void solve () { int i, j, t; tc = 0 ; for (i = 1 ; i <= tb; ++ i) { t = 0 ; for (int j = 0 ;j < 8 ;j ++){ if (!(a[ta] < node (b[i].x + dx[j] , b[i].y + dy[j]) || *lower_bound (a + 1 , a + ta + 1 , node (b[i].x + dx[j] , b[i].y + dy[j])) != node (b[i].x + dx[j] , b[i].y + dy[j]))) t ++; } if (t == 3 || (t == 2 && !(a[ta] < b[i] || *lower_bound (a + 1 , a + ta + 1 , b[i]) != b[i]))) c[++tc] = b[i]; } sort (c + 1 , c + tc + 1 ); for (i = 1 ; i <= tc; ++ i) a[i] = c[i]; ta = tc; } inline int thestars () { cin >> ta >> T; for (int i = 1 ; i <= ta; ++ i) cin >> a[i].x >> a[i].y; sort (a + 1 , a + ta + 1 ); while (T --) work (), solve (); printf ("%d\n" , ta); for (int i = 1 ; i <= ta; ++ i) printf ("%d %d\n" , a[i].x, a[i].y); return 0 ; } int youngore = thestars ();signed main () {;}
#下午
讲课,数论与概率期望
关于数学的知识比较杂,首先是一些前置知识
%
\((a+b)\;mod\;p =
(a\;mod\;p\;+b\;mod\;p)\;mod\;p\)
\((a*b)\;mod\;p =
(a\;mod\;p\;*b\;mod\;p)\;mod\;p\)
\(a\;mod\;p=b\;mod\;p\Longleftrightarrow\;p\mid(a-b)\)
快速幂
ksm_递归
#define int long long
inline int ksm(int a, int b, int mod) {
if (!b) return a%mod;
if (b&1) return a*ksm(a, b-1, mod);
int tmp = ksm(a, (b>>1), mod)%mod;
return tmp*tmp%mod;
}
ksm_for
inline int ksm(int a, int b, int mod) {
int res = 1;
while(b) {
if (b&1) res = res*a%mod;
a = a*a%mod;
b >>= 1;
}
return res;
}
基本算术定理
质因子分解的办法:
试除法:枚举
试除法的优化(埃拉托色尼筛法):预处理指数,枚举倍数
欧拉筛:在埃氏筛的基础上进行优化,线性筛的基础上记录下每个数的最小质因子
给出埃氏筛代码:
埃氏筛
memset (v, 1, sizeof v);
v[1] = 0;
for (int i = 2; i <= N; ++ i) {
if (v[i]) prime[++ cnt] = i;
for (int j = 1; j <= cnt && i*prime[j] <= N; ++ j)
v[i*prime[j]] = 0;
}
给出欧拉筛代码:
欧拉筛
memset (v, 1, sizeof v);
v[1] = 0;
for (int i = 2; i <= N; ++ i) {
if (v[i]) prime[++ cnt] = i;
for (int j = 1; j <= cnt && i*prime[j] <= N; ++ j) {
v[i*prime[j]] = 0;
if (i%prime[j] == 0) break;
}
}
考虑欧拉筛是如何优化的?在埃氏筛中,每一个数字可能会被多次筛到,浪费了时间复杂度,而欧拉筛中每个只会被筛到一次,且是由他的最小质因子筛出来的
考虑如下:
\(i = 2\) 筛出\(4\) ,\(i
=3\) 筛出\(6,9\) ,\(i=4\) 筛出\(8\) ,\(i=5\) 筛出\(10,15,25\) ,\(i=6\) 筛出\(12\)
显然每个被\(i\) 筛出的数的最小质因子都是\(i\)
枚举约数的办法:
1.试除法:枚举\(1\) 到\(\sqrt n\)
2.筛法:预处理,枚举\(1\) 到\(n\) 的数,再枚举其倍数,则这个数是倍数的约数,可以用\(vector\) 存起来,由调和级数可知复杂度为\(O(n*ln_n)\)
公约数与公倍数
设\(A=p^{a_1}_1p^{a_2}_2...p^{a_n}_n,B =
p^{b_1}_1p^{b_2}_2...p^{b_n}_n\)
因此:
\(gcd(A,B) =
p^{min(a_1,b_1)}_1p^{min(a_2,b_2)}_2...p^{min(a_n,b_n)}_n\)
$ lcm(A, B) =
p^{max(a_1,b_1)}_1p^{max(a_2,b_2)}_2...p^{max(a_n,b_n)}_n$
\(gcd(A,B)*lcm(A,B) = A*B\)
GCD
inline int gcd(int a, int b){return !b?a:gcd(b,a%b);}
下面是一些例题:
核聚变反应程度
click
巧题,次大公约数一定是最大公约数除掉最小的质因数
甩一个题解
给出AC代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <bits/stdc++.h> #define int long long #define debug using namespace std;const int N = 1e5 +66 ;int n, len, a[N];vector<int >q; inline int gcd (int a, int b) {return !b?a:gcd (b,a%b);}inline int thestars () { scanf ("%lld" , &n); for (int i = 1 ; i <= n; ++ i) scanf ("%lld" , &a[i]); int now = a[1 ]; for (int i = 2 ; i * i <= now; ++ i) { if (now%i == 0 ) { while (now%i == 0 ) now /= i; q.push_back (i); ++ len; } } if (now > 1 ) q.push_back (now), ++ len; for (int i = 1 ; i <= n; ++ i) { int tmp = gcd (a[1 ], a[i]); if (tmp == 1 ) printf ("-1 " ); else { for (int i = 0 ; i < len; ++ i) { if (tmp%q[i] == 0 ) { printf ("%lld " , tmp/q[i]); break ; } } } } return 0 ; } int youngore = thestars ();signed main () {;}
Divisors
click
开桶记录每个数字出现多少次
其中\((1,4)(4,1)\) 算两次
给出AC代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include <bits/stdc++.h> #define int long long #define debug using namespace std;const int N = 3e6 +250 ;int n, res, maxn;int a[N], b[N];inline int thestars () { scanf ("%d" , &n); for (int i = 1 ; i <= n; ++ i) { scanf ("%d" , &a[i]); ++ b[a[i]]; maxn = max (a[i], maxn); } for (int i = 1 ; i <= maxn; ++ i) { if (b[i]) { res += b[i]*(b[i]-1 ); for (int j = i<<1 ; j <= maxn; j += i) if (b[j]) res += b[i]*b[j]; } } cout << res; return 0 ; } int youngore = thestars ();signed main () {;}
扩展欧几里得
是求方程\(𝑎𝑥+𝑏𝑦=gcd(𝑎,𝑏)\) 的一组整数解的一种算法
对于一个方程:\(a*x+b*y=gcd(a,b)\) ,我们有如下推导
设有式子\(a*x_1+b*y_1=gcd(a,b)\)
根据欧几里得算法可得:\(b*x_2+(a\%b)*y_2=gcd(b,a\%b)\)
观察\(b*x_2+(a\%b)*y_2\) ,这个式子,我们可以将\((a\%b)\) 写作\((a-\lfloor\frac{a}{b}\rfloor*b)\)
将括号打开常数\(a,b\) 合并,合并之后的结果为 \(a*y_2+b*(x_2-\lfloor\frac{a}{b}\rfloor*y_2)\)
由于欧几里得算法的原理\(gcd(a,b)==gcd(b,a\%b)\)
我们将两式子联立,对比系数即可得到\(x_1=y_2,y_1=x_2-\lfloor\frac{a}{b}\rfloor*y_2\)
附通解的求法:设得到的特殊解为\(x = x_0, y
= y_0\)
则通解为\(x = x_0+\dfrac {b} {gcd(a,b)}*t,
y = y_0 - \dfrac{a}{gcd(a, b)}*t\) ,其中\(t\) 为正整数
考虑证明。
给出代码:
EXgcd
inline void calc (int a, int b, int &x, int &y) {
if (!b) x = 1, y = 666;
else calc (b, a%b, y, x), y -= a/b*x;
}
同余方程
click
原式子\(ax \equiv 1 \pmod
b\Longleftrightarrow ax+by=1\)
题目保证有解,根据裴蜀定理可以知道\(gcd(a,b) =1\) ,直接用\(EXgcd\) 就可以
给出AC代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <bits/stdc++.h> #define int long long using namespace std;int a, b, x, y;inline void calc (int a, int b, int &x, int &y) { if (!b) x = 1 , y = 666 ; else calc (b, a%b, y, x); y -= a/b*x; } main () { cin >> a >> b; calc (a, b, x, y); x = (x%b+b)%b; cout << x; return 0 ; }
PS :y尽量从0开始,因为从0开始的话不容易爆\(int\)
乘法逆元
click
若\(a*x\equiv 1 (mod\;b )\)
并且\(a ,b\) 互质.我们就称\(x\) 为 \(a\) 在\(mod
\;b\) 意义下的乘法逆元,记为\(a^{-1}\)
求逆元的click
仪仗队
把左下角看作$(0,0) \(,右上角看作\) (n-1,n-1)$
,那么能看到当且仅当横纵坐标互质
然后我们手动盖住上半部分,但是得漏出对角线,答案就是\(1 +
\sum_\limits{i=1}^{n-1}\phi(i)\) ,又因为上半部分对称相等,所以重复算了\(1\) ,因此要减去\(1\) ,又因为左右两边的\(2\) 没有算,因此要加2
所以总答案为:\(2*\sum_\limits{i=1}^{n-1}\phi(i) + 1\)
沙拉公主的困惑
click
由于\(N!\) 是\(M!\) 的倍数,而若\(a\) 与\(b\) 互质则\(a+b\) 与\(b\) 互质,故\(N!\) 中每$M! \(个便有\) φ(M!)$ 个与$M! $互质
然后答案呼之欲出:
\(\dfrac {N!} {M!}* \phi(M!) = \dfrac {N!}
{M!}*M!*\sum_\limits {p_i \mid M!} \dfrac {p_i-1} {p_i} =
N!*\sum_\limits{p_i<=M} \dfrac{p_i-1}{p_i}\)
然后手玩逆元
欧拉定理
Longge问题
click
枚举最大公约数为d ,则数目就是\(\dfrac N
d\) ,答案为\(\sum_\limits{d\mid
N}d*\phi(\dfrac N d)\)
因此枚举约数再求欧拉,时间复杂度大概是O(算不出来但是能过)
复杂度\(O(玄)\)
(我不会…..)
接下来是矩阵乘法
斐波那契数列
click
主要是我不会打矩形....
路径计数
矩阵的\(k\) 次方就是答案
晚上
写博客补坑