T20200901

T1 锻造(forging)

就是一期望\(\text{Dp}\) \[ \begin{align*} f(i)&=f(i-1)+f(i-2)+(1-K)(f(i)-f(i-2))\\ f(i)&=f(i-1)+f(i-2)+f(i)-f(i-2)-Kf(i)+Kf(i-2)\\ Kf(i)&=f(i-1)+Kf(i-2)\\ f(i)&=\frac{c_{i-1}}kf(i-1)+f(i-2) \end{align*} \]

Code

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
#include <bits/stdc++.h>

using namespace std;

const int Maxn = 1e7 + 15, Mod = 998244353;
int n, a;
int bx, by, cx, cy, p;
int b[Maxn], c[Maxn], f[Maxn], inv[Maxn] = {0, 1};

int main()
{
scanf ("%d %d", &n, &a);
scanf ("%d %d %d %d %d", &bx, &by, &cx, &cy,&p);
b[n] = b[0] = by + 1, c[n] = c[0] = cy + 1;
for (int i = 1; i < n; ++i)
{
b[i] = (1ll * b[i - 1] * bx + by) % p + 1; b[n] = max(b[i], b[n]);
c[i] = (1ll * c[i - 1] * cx + cy) % p + 1; c[n] = max(c[i], c[n]);
}
b[n] = max(b[n], c[n]);
for (int i = 2; i <= b[n]; ++i) inv[i] = 1ll * (Mod - Mod / i) * inv[Mod % i] % Mod;
f[0] = a, f[1] = (1ll * inv[min(c[0], b[0])] * c[0] % Mod * f[0] % Mod + f[0]) % Mod;
for (int i = 2; i <= n; ++i) f[i] = (1ll * inv[min(c[i - 1], b[i - 2])] * c[i - 1] % Mod * f[i - 1] % Mod + f[i - 2]) % Mod;
printf ("%d\n", f[n] % Mod);
}

T2 整除(division)

\(n|x^m-x\),求在\([1,n]\)有多少个解

考虑乱搞一下式子 \[ x^m-x=kn\\ x^m\equiv x\pmod n \] 然后\(\text{n}\)又是一个无平方因子数

所以时可以拆开乱搞的

\(\text{n}\)的每个因子进行一次操作,把答案乘起来即可

这个严格的证明应该是同余方程之类的东西?

做题的话其实是可以猜结论的

Code

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
69
70
71
72
73
74
75
#include <bits/stdc++.h>

using namespace std;

const int Maxn = 1e4, Mod = 998244353;
int ID, T;
int C, M, Tmp;
int Pr[Maxn + 10], Pw[Maxn + 10];
bool Vis[Maxn + 10];

inline int Read()
{
int X(0);
char O(getchar());
while (O < '0' || O > '9') O = getchar();
for (; O >= '0' && O <= '9'; O = getchar()) X = (X << 1) + (X << 3) + (O ^ 48);
return X;
}

inline void Init()
{
for (int i = 2; i <= Maxn; ++i)
{
if (!Vis[i]) Pr[++Pr[0]] = i;
for (int j = 1; j <= Pr[0] && i * Pr[j] <= Maxn; ++j)
{
Vis[i * Pr[j]] = 1;
if (i % Pr[j] == 0) break;
}
}
}

inline int Pow(int X, int Y, int Mod)
{
int Ans(1);
while (Y)
{
if (Y & 1) Ans = 1ll * Ans * X % Mod;
X = X * X % Mod;
Y >>= 1;
}
return Ans % Mod;
}

inline int GetAns(int M, int P)
{
Pw[1]= 1, Pw[P] = 1;
for (int i = 2; i < P; ++i)
{
if (!Vis[i]) Pw[i] = Pow(i, M, P);
for (int j = 1; j <= Pr[0] && i * Pr[j] <= P; ++j)
{
Pw[i * Pr[j]] = Pw[i] * Pw[Pr[j]] % P;
if (i % P == 0) break;
}
}
for (int i = 1; i < P; ++i)
if (Pw[i] == i) ++Pw[P];
return Pw[P];
}

int main()
{
freopen ("division.in", "r", stdin);
freopen ("division.out", "w", stdout);
Init();
ID = Read(), T = Read();
while (T--)
{
C = Read(), M = Read();
int Ans(1);
while (C--) Ans = 1ll * Ans * GetAns(M, Read()) % Mod;
printf ("%d\n", Ans);
}
}

T3 欠钱(money)

树上启发式合并

有根树\(LCT\)

鸽着?

Code

\(\text{YJYX}\)巨佬的

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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <algorithm>

#define LL long long
#define FOR(i,A,B) for(int i=A;i<=B;i++)
#define BOR(i,A,B) for(int i=A;i>=B;i--)
#define Cl(X,Y) memset((X),(Y),sizeof(X))
#define INF 0x3f3f3f3f
#define MOD 998244353
#define FOR_SIDE(i,A) for(int i=Head[A];i;i=Next[i])
using namespace std;
const int MAXN=1e5+10,MAXM=1e6+10;

int Last,Total,Test;
int Next[MAXM<<1],End[MAXM<<1],Head[MAXN],Val[MAXM<<1],Kind[MAXM<<1],Cur;
int Root[MAXN],Dep[MAXN],Size[MAXN];
int Anc[MAXN][20],Min[MAXN][20],Dir[MAXN][20];
int u,v,w,Opt;

inline void File() {
freopen("money.in","r",stdin);
freopen("money.out","w",stdout);
}

inline void DFS(int New,int Pre,int Top) {
Root[New]=Top;
Dep[New]=Dep[Pre]+1;
FOR(i,1,17) {
Anc[New][i]=Anc[Anc[New][i-1]][i-1];
Min[New][i]=min(Min[New][i-1],Min[Anc[New][i-1]][i-1]);
Dir[New][i]=(Dir[New][i-1] | Dir[Anc[New][i-1]][i-1]);
}
FOR_SIDE(i,New) {
if(End[i]==Pre) continue;
Anc[End[i]][0]=New;
Min[End[i]][0]=Val[i];
Dir[End[i]][0]=(Kind[i] ^ 3);
DFS(End[i],New,Top);
}
}

inline void Add_Edge(int From,int To,int Temp) {
Next[++Cur]=Head[From];
Head[From]=Cur;
End[Cur]=To;
Val[Cur]=Temp;
Kind[Cur]=1;
Next[++Cur]=Head[To];
Head[To]=Cur;
End[Cur]=From;
Val[Cur]=Temp;
Kind[Cur]=2;
}

inline void Update(int From,int To,int Temp) {
Add_Edge(From,To,Temp);
int Base=1;
if(Size[Root[From]]>Size[Root[To]]) Base=2,swap(From,To);
Size[Root[To]]+=Size[Root[From]];
Anc[From][0]=To;
Min[From][0]=Temp;
Dir[From][0]=Base;
DFS(From,To,Root[To]);
}

inline int Get(int From,int To) {
int Base=1,Ans=INF;
if(Dep[From]<Dep[To]) Base=2,swap(From,To);
BOR(i,17,0)
if(Dep[From]-(1<<i)>=Dep[To]) {
if(Dir[From][i]!=Base) return 0;
Ans=min(Ans,Min[From][i]);
From=Anc[From][i];
}
if(From==To) return Ans;
BOR(i,17,0) {
if(Anc[From][i]!=Anc[To][i]) {
if(Dir[From][i]!=Base || Dir[To][i]!=(Base ^ 3)) return 0;
Ans=min(Ans,min(Min[From][i],Min[To][i]));
From=Anc[From][i];
To=Anc[To][i];
}
}
if(Dir[From][0]!=Base || Dir[To][0]!=(Base ^ 3)) return 0;
Ans=min(Ans,min(Min[From][0],Min[To][0]));
return Ans;
}

int main() {
File();
scanf("%d %d",&Total,&Test);
FOR(i,1,Total) Root[i]=i,Size[i]=1;
while(Test--) {
scanf("%d %d %d",&Opt,&u,&v);
u=(u+Last)%Total+1;
v=(v+Last)%Total+1;
if(Opt==0) {
scanf("%d",&w);
w=(w+Last)%Total+1;
Update(u,v,w);
} else { printf("%d\n",Last=Get(u,v)); }
}
return 0;
}