# Active Thought Training 4 | CF Number Theory 2000+ | Last Five Questions

Keywords: Algorithm number theory

# G: The LCMs Must be Large | CF 1166E

## meaning of the title

• The LCMs Must be Large | CF 1166E
Given a n n n
given m m m groups of data, each set of data is a collection S S S, the elements of each collection are in [ 1 , n ] [1,n] Scope of [1,n], and set size < n <n <n
Ask if there is one a n a_n an, satisfies for each set of data, satisfies L C M ( S ) > L C M ( I − S ) LCM(S)>LCM(I-S) LCM(S)>LCM(I−S)
That is, the minimum common multiple of the number of the selected set is greater than the minimum common multiple of the other unselected elements.
1 ≤ m ≤ 50 1\le m\le 50 1≤m≤50
1 ≤ n ≤ 1 0 4 1\le n\le 10^4 1≤n≤104

## thinking

• With a look at the mask, you can see that if two sets of data satisfy that their intersection is empty, there must be no answer. Otherwise, there must be an answer.
Very good, just do exercises after class (X
We can prove that the answer exists by constructing it.
Let's take it out first m m m prime numbers p 1 , p 2 , ⋯   , p m p_1,p_2,\cdots,p_m p1​,p2​,⋯,pm​
If j j Group j data contains a i a_i ai, then we'll let a i a_i ai Inclusion Factor p j p_j pj​
In this way, L C M ( S ) = ∏ i = 1 m p i LCM(S)=\prod_{i=1}^m p_i LCM(S) =i=1m pi, and L C M ( I − S ) < L C M ( S ) LCM(I-S)<LCM(S) LCM(I_S)<LCM(S) because it does not contain a prime factor p j p_j pj​
The requirement is that the intersection of any two sets of data is not null.
• So our question is how to tell if the intersection is not empty.
Violence for each two groups, one at a time v i s vis vis judgment, withdrawal.

## Code

• Time Complexity: O ( m 2 n ) O(m^2n) O(m2n)
#include<bits/stdc++.h>
using namespace std;
void show(){std::cerr << endl;}template<typename T,typename... Args>void show(T x,Args... args){std::cerr << "[ " << x <<  " ] , ";show(args...);}
typedef long long ll;
const int MAX = 1e4+50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;

int num[MAX];
vector<int>V[MAX];

int main()
{
int m,n;scanf("%d%d",&m,&n);
for(int i = 1;i <= m;++i){
int si;scanf("%d",&si);
while(si--){
int t;scanf("%d",&t);
V[i].push_back(t);
}
}

for(int i = 1;i <= m;++i)
for(int j = i + 1;j <= m;++j){
bool jiao = false;
for(auto it : V[i])num[it]++;
for(auto it : V[j])if(num[it])jiao = true;

if(!jiao){
puts("impossible");
return 0;
}
for(auto it : V[i])num[it]--;
}
puts("possible");
return 0;
}


# H: Calendar Ambiguity | CF 1389E

## meaning of the title

• Calendar Ambiguity | CF 1389E
One year has m m m months, each month has d d d days, every w w w days are a week.
Ask how many pairs ( x , y ) (x,y) (x,y), satisfied x < y x<y X<y and x x Month x y y y-day and y y Month y x x Day x is the same day of the week. (Like Wednesday, or Week) 88 88 88 and so on)
• 1000 1000 1000 sets of samples
1 ≤ m , d , w ≤ 1 0 9 1\le m,d,w\le 10^9 1≤m,d,w≤109

## thinking

• A naked math problem.
List Formula, Nude Formula is ( x − 1 ) d + y ≡ ( y − 1 ) d + x ( m o d w ) (x-1)d+y\equiv (y-1)d+x \pmod w (x−1)d+y≡(y−1)d+x(modw)
After simplification becomes x ( d − 1 ) ≡ y ( d − 1 ) ( m o d w ) x(d-1)\equiv y(d-1) \pmod w x(d−1)≡y(d−1)(modw)
Considering the division of the congruent equation, we divide both sides of the equation by d − 1 d-1 d_1, modulus divided by modulus and divisor gcd ⁡ \gcd gcd
• So that's equivalent to what we're asking for x ≡ y ( m o d p ) x\equiv y\pmod p x≡y(modp)， 1 ≤ x < y ≤ min ⁡ ( m , d ) 1\le x<y\le \min(m,d) Number of schemes with 1 < x < y < min(m,d)
Consideration is too strict. We remember min ⁡ ( m , d ) = u p \min(m,d)=up min(m,d)=up, so we can figure it out first 1 ≤ x , y ≤ u p 1\le x,y\le up Number of schemes with 1 < x,y < up
Then subtract x = y x=y Number of schemes x=y (total) e d ed ed), and then consider symmetry, divided by two is the answer we need
• So that's equivalent to what we're asking for x ≡ y ( m o d p ) x\equiv y\pmod p x≡y(modp) ， 1 ≤ x , y ≤ u p 1\le x,y\le up Number of schemes with 1 < x,y < up
Let's press the pattern p p p-equivalent class partition. Assuming partitioning k + 1 k+1 k+1 segment, where the range of the previous segment is [ 1 , p ] , [ p + 1 , 2 p ] , ⋯ [1,p],[p+1,2p],\cdots [1,p],[p+1,2p],⋯
The last paragraph is [ k p + 1 , u p ] [kp+1,up] [kp+1,up]
We remember s 1 s1 s1 represents the number of alternatives for the last paragraph. s 2 s2 s2 representation p − s 1 p-s1 p−s1
Our final answer is s 1 ∗ ( k + 1 ) 2 + s 2 ∗ k 2 s1*(k+1)^2+s2*k^2 s1(k+1)2+s2_k2, think about why

## Code

• Time Complexity: O ( T log ⁡ ) O(T\log) O(Tlog)
#include<bits/stdc++.h>
using namespace std;
void show(){std::cerr << endl;}template<typename T,typename... Args>void show(T x,Args... args){std::cerr << "[ " << x <<  " ] , ";show(args...);}
typedef long long ll;
const int MAX = 1e4+50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;

int main()
{
int T;
cin >> T;
while(T--){
ll m,d,w;cin >> m >> d >> w;
ll p = w / __gcd(w,d-1);
ll up= min(m,d);
ll k = up / p;
ll s1,s2;
s1 = up - k * p;
s2 = p - s1;
ll ans = s1 * (k + 1) * (k + 1) + s2 * k * k;
ans -= min(m,d);
ans /= 2;
cout << ans << endl;
}
return 0;
}


# I: Kate and imperfection | CF 1333F

## meaning of the title

• Kate and imperfection | CF 1333F
Given a set S = { 1 , 2 , 3 , ⋯   , n } S=\{1,2,3,\cdots,n\} S={1,2,3,⋯,n}
about I k I_k Ik, which means you want to choose from k k k elements, for all in I k I_k Element pairs of Ik ( x , y ) (x,y) (x,y), you need to max ⁡ { gcd ⁡ ( x , y ) } \max\{\gcd(x,y)\} max{gcd(x,y)} is the smallest.
For each I 2 , ⋯   , I n I_2,\cdots,I_n I2,..., In, you'll all ask what this minimum is
• 2 ≤ n ≤ 5 ⋅ 1 0 5 2\le n\le 5\cdot 10^5 2≤n≤5⋅105

## thinking

• We can assume first n n n is very large. Assume there are p p p prime numbers, so let's pick them first. 1 1 1 Selected also has no effect on the answer. So until I p + 1 I_{p+1} Ip+1 is still 1 1 1
• Larger, we have to add the totals. Assuming that the prime factor of a complex number is decomposed into a ∗ b ∗ c a*b*c a_b_c, and a < b < c a<b<c A<b<c, then when it comes in, at this point max ⁡ { gcd ⁡ ( x , y ) } \max\{\gcd(x,y)\} max{gcd(x,y)} is at least max ⁡ { a , b , c } \max\{a,b,c\} max{a,b,c}.
And then discovery adds in first 4 4 4 must be optimal. Then add 6 6 6 instead of plus 8 8 8 because gcd ⁡ ( 4 , 8 ) = 4 > gcd ⁡ ( 3 , 6 ) = 3 \gcd(4,8)=4>\gcd(3,6)=3 gcd(4,8)=4>gcd(3,6)=3
And then we find that the worst answer to our new number is x / m i n _ p r i m e x x/min\_prime_x x/min_primex​
• That is, for each number, we calculate its minimum prime factor, divide the number by its minimum factor, and then greed for the smallest one at a time, which is optimal.

## Code

• Time Complexity: O ( n log ⁡ n ) O(n\log n) O(nlogn)
#include<bits/stdc++.h>
using namespace std;
void show(){std::cerr << endl;}template<typename T,typename... Args>void show(T x,Args... args){std::cerr << "[ " << x <<  " ] , ";show(args...);}
typedef long long ll;
const int MAX = 5e5+50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;

int tot;
bool vis[MAX];
int pri[MAX];
int mp[MAX];
int ans[MAX];
void shai(int n){
mp = 1;
for(int i = 2;i <= n;++i){
if(!vis[i]){
pri[++tot] = i;
mp[i] = i;
}
for(int j = 1;j <= tot && i * pri[j] <= n;++j){
vis[i * pri[j]] = 1;
mp[i * pri[j]] = pri[j];
if(i % pri[j] == 0){
break;
}
}
}
for(int i = 2;i <= n;++i){
ans[i] = i / mp[i];
}
sort(ans+2,ans+n+1);
}
int main()
{
int n;
scanf("%d",&n);
shai(n);
for(int i = 2;i <= n;++i){
printf("%d ",ans[i]);
}
return 0;
}


# J: Infinite Path | CF 1327D

## meaning of the title

• J: Infinite Path | CF 1327D
Given a full permutation p n p_n pn​
Given an array of colors c n c_n cn​
Give a token p × p p\times p p × p is to let p [ i ] = p [ p [ i ] ] p[i]=p[p[i]] p[i]=p[p[i]]
Give a token p k = ∏ i = 1 k p p^k=\prod_{i=1}^k p pk=∏i=1k​p
Defining an infinite path is p [ i ] , p [ p [ i ] ] , p [ p [ p [ i ] ] ] , ⋯ p[i],p[p[i]],p[p[p[i]]],\cdots p[i],p[p[i]],p[p[p[i]]],⋯
• Find the smallest k k k， k ≥ 1 k\ge 1 k < 1, satisfied p k p^k pk has at least one infinite path, where each point has the same color
• 1 ≤ n ≤ 2 ⋅ 1 0 5 1\le n\le 2\cdot 10^5 1≤n≤2⋅105

## thinking

• (1) First of all, the whole arrangement must form some rings. Each of our rings can be considered separately.
(2) This ring has a length of c n t cnt cnt, then p k p^k The number of rings that pk produces is gcd ⁡ ( k , c n t ) \gcd(k,cnt) gcd(k,cnt)
We can f o r for for each ring, and then f o r for for each k k k, and then determine if the new ring has the same color inside.
(3) But it looks like we don't need to f o r for for each k k k, for different k k k but have the same gcd ⁡ \gcd gcd, these k k k I just need to pick one, because they are all equivalent. So we chose k k The number of k decreases to the order of magnitude of the factor O ( c n t 1 / 3 ) O(cnt^{1/3}) O(cnt1/3)
(4) How do I know quickly p k p^k What is each point of pk?
I take out the point of a ring and write it down as c 1 , c 2 , ⋯   , c c n t c_1,c_2,\cdots,c_{cnt} c1​,c2​,⋯,ccnt​
p [ i ] = c ( i + 1 ) % c n t p[i]=c_{(i+1) \% cnt} p[i]=c(i+1)%cnt​
p [ p [ i ] ] = c ( i + 2 ) % c n t p[p[i]]=c_{(i+2) \% cnt} p[p[i]]=c(i+2)%cnt​
p k [ i ] = c ( i + k ) % c n t p^k[i]=c_{(i+k) \% cnt} pk[i]=c(i+k)%cnt​

## Code

• Time Complexity: O ( n 3 / 4 ) O(n^{3/4}) O(n3/4)
#include<bits/stdc++.h>
using namespace std;
void show(){std::cerr << endl;}template<typename T,typename... Args>void show(T x,Args... args){std::cerr << "[ " << x <<  " ] , ";show(args...);}
typedef long long ll;
const int MAX = 5e5+50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;

int ans;
int nxt[MAX];
int col[MAX];
bool vis[MAX];

vector<int>V;

int duo;
int duovis[MAX];

bool sam;

int t_per[MAX];

void dfs(int now,int c){
if(col[now] != c){sam = false;}
duovis[now] = duo;

int nxxt = t_per[now];
if(duovis[nxxt] != duo)dfs(nxxt,c);
}

void check(int cnt,int stp){
duo++;

for(int i = 0;i < cnt;++i){
t_per[V[i]] = V[(i+stp)%cnt];
}

for(int i = 0;i < cnt;++i){
int now = V[i];
if(duovis[now] == duo)continue;
sam = true;
dfs(now,col[now]);
if(sam){
ans = min(ans,stp);
return;
}
}
}

void work(int S){
V.clear();
int now = S;
while(!vis[now]){
vis[now] = 1;
V.push_back(now);
now = nxt[now];
}
int cnt = V.size();
for(int i = 1;i * i <= cnt;++i){
if(cnt % i == 0){
check(cnt,i);
check(cnt,cnt/i);
}
}
}

int main()
{
int T;scanf("%d",&T);
while(T--){
int n;scanf("%d",&n);
for(int i = 0;i < n;++i)vis[i] = 0;
for(int i = 0;i < n;++i)scanf("%d",&nxt[i]),nxt[i]--;
for(int i = 0;i < n;++i)scanf("%d",&col[i]);
ans = n;
for(int i = 0;i < n;++i){
if(vis[i])continue;
work(i);
}
printf("%d\n",ans);
}
return 0;
}


# K: Multiples and Power Differences | CF 1485D

## meaning of the title

• Multiples and Power Differences | CF 1485D
My construction is really rubbish...
Given a Matrix a n , m a_{n,m} an,m​
You need to construct a matrix b n , m b_{n,m} bn,m, meets the following requirements:
(1) a i , j ∣ b i , j a_{i,j}|b_{i,j} ai,j​∣bi,j​
(2) For b b b Two values adjacent to the middle edge, whose difference is the fourth power of a positive integer.
(3) 1 ≤ b i , j ≤ 1 0 6 1\le b_{i,j}\le 10^6 1≤bi,j​≤106
• 2 ≤ n , m ≤ 500 2\le n,m\le 500 2≤n,m≤500
1 ≤ a i , j ≤ 16 1\le a_{i,j}\le 16 1≤ai,j​≤16

## thinking

• Is the difference the fourth power of a positive integer? Can this be done?
Well, here's a magical tip: l c m ( 1 , 2 , 3 , ⋯   , 16 ) = 720720 lcm(1,2,3,\cdots,16)=720720 lcm(1,2,3,⋯,16)=720720
This number < 1 0 6 <10^6 <106
• And the answers are scarce, and violent search for pruning is not enough. Next comes the magical construction
If i + j i+j i+j is an odd number, so b i , j = 720720 b_{i,j}=720720 bi,j​=720720
Otherwise, b i , j = 720720 + a i , j 4 b_{i,j}=720720+a_{i,j}^4 bi,j​=720720+ai,j4​
Wow, it's so easy to see, but it's hard to think of all at once...

## Code

• Time Complexity: O ( n 2 ) O(n^2) O(n2)
#include<bits/stdc++.h>
using namespace std;
void show(){std::cerr << endl;}template<typename T,typename... Args>void show(T x,Args... args){std::cerr << "[ " << x <<  " ] , ";show(args...);}
typedef long long ll;
const int MAX = 5e5+50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;

int main()
{
int n,m;cin >> n >> m;
for(int i = 1;i <= n;++i){
for(int j = 1;j <= m;++j){
int t;cin >> t;
if((i+j)&1)cout << 720720 << " ";
else cout << 720720 + t * t * t * t << " ";
}
puts("");
}
return 0;
}


Posted by mikkex on Fri, 12 Nov 2021 12:20:26 -0800