数论刷题总结1

E. Gardener and Tree
time limit per test4 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
A tree is an undirected connected graph in which there are no cycles. This problem is about non-rooted trees. A leaf of a tree is a vertex that is connected to at most one vertex.

The gardener Vitaly grew a tree from n vertices. He decided to trim the tree. To do this, he performs a number of operations. In one operation, he removes all leaves of the tree.

Example of a tree.
For example, consider the tree shown in the figure above. The figure below shows the result of applying exactly one operation to the tree.

The result of applying the operation “remove all leaves” to the tree.
Note the special cases of the operation:

applying an operation to an empty tree (of 0 vertices) does not change it;
applying an operation to a tree of one vertex removes this vertex (this vertex is treated as a leaf);
applying an operation to a tree of two vertices removes both vertices (both vertices are treated as leaves).
Vitaly applied k operations sequentially to the tree. How many vertices remain?

Input
The first line contains one integer t (1≤t≤104) — the number of test cases. Then t test cases follow.

Each test case is preceded by an empty line.

Each test case consists of several lines. The first line of the test case contains two integers n and k (1≤n≤4⋅105, 1≤k≤2⋅105) — the number of vertices in the tree and the number of operations, respectively. Then n−1 lines follow, each of them contains two integers u and v (1≤u,v≤n, u≠v) which describe a pair of vertices connected by an edge. It is guaranteed that the given graph is a tree and has no loops or multiple edges.

It is guaranteed that the sum of n from all test cases does not exceed 4⋅105.

Output
For each test case output on a separate line a single integer — the number of vertices that remain in the tree after applying k operations.
补上周div3题,E题简单数据结构但是还不会,血亏。
把度为1存起来,然后遍历去点

#include<bits/stdc++.h>
using namespace std;
const int N=4e5+10;
int t,n,k,u,v,vis[N],deg[N],res;
vector<int> g[N];
int main(){
    ios::sync_with_stdio(0);
    cin>>t;
    while(t--){
        res=0;
        for(int i=0;i<=n;i++){
            g[i].clear();
            vis[i]=deg[i]=0;
        }
        cin>>n>>k;
        if(n==1){
            cout<<0<<endl;
            continue;
        }
        for(int i=1;i<n;i++){
            cin>>u>>v;
            g[u].push_back(v);
            g[v].push_back(u);
            deg[u]++,deg[v]++;
        }
        queue<int> q;
        for(int i=1;i<=n;i++){
            //cout<<i<<' '<<deg[i]<<endl;
            if(deg[i]==1){
                q.push(i);
                vis[i]=1;
            }
        }

        while(!q.empty()){
            int t=q.front();
            //cout<<t<<endl;
            if(vis[t]<=k)res++;
            q.pop();
            for(int i=0;i<g[t].size();i++){
                int y=g[t][i];
                deg[y]--;
                if(deg[y]==1){
                    q.push(y);
                    vis[y]=vis[t]+1;
                }
            }
        }
        cout<<n-res<<endl;



    }
	return 0;
}

P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题
题目描述
输入两个正整数 x_0, y_0x
0

,y
0

,求出满足下列条件的 P, QP,Q 的个数:

P,QP,Q 是正整数。

要求 P, QP,Q 以 x_0x
0

为最大公约数,以 y_0y
0

为最小公倍数。

试求:满足条件的所有可能的 P, QP,Q 的个数。

输入格式
一行两个正整数 x_0, y_0x
0

,y
0

输出格式
一行一个数,表示求出满足条件的 P, QP,Q 的个数。

输入输出样例
输入 #1复制
3 60
输出 #1复制
4
从a开始枚举,如果是b的因数,则判断根据ab之积为其gcd与lcm之积,推出另一个数,在判断是否符合条件。

#include<bits/stdc++.h>
using namespace std;
int main(){
    long long a,b,res=0;
    cin>>a>>b;
    for(long long i=a;i*i<=b*a;i+=a){
        if(b%i==0&&__gcd(i,a*b/i)==a){
            res+=2;
            if(i==a*b/i)res--;
        }
    }
    cout<<res<<endl;


	return 0;
}

P4549 【模板】裴蜀定理
题目描述
给定一个包含 nn 个元素的整数序列 AA,记作 A_1,A_2,A_3,…,A_nA
1

,A
2

,A
3

,…,A
n

求另一个包含 nn 个元素的待定整数序列 XX,记 S=\sum\limits_{i=1}^nA_i\times X_iS=
i=1

n

A
i

×X
i

,使得 S>0S>0 且 SS 尽可能的小。

输入格式
第一行一个整数 nn,表示序列元素个数。

第二行 nn 个整数,表示序列 AA。

输出格式
一行一个整数,表示 S>0S>0 的前提下 SS 的最小值。

输入输出样例
输入 #1复制
2
4059 -1782
输出 #1复制
99
根据ax+by的最小整数解为gcd(a,b)可得,求出改序列的公因数

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll a[100010];
int main(){
    ll n,res=0;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        res=__gcd(res,a[i]);
    }
    cout<<abs(res);
	return 0;
}

P2158 [SDOI2008] 仪仗队
题目描述
作为体育委员,C 君负责这次运动会仪仗队的训练。仪仗队是由学生组成的 N \times NN×N 的方阵,为了保证队伍在行进中整齐划一,C 君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。

现在,C 君希望你告诉他队伍整齐时能看到的学生人数。

输入格式
一行,一个正整数 NN。

输出格式
输出一行一个数,即 C 君应看到的学生人数。

输入输出样例
输入 #1复制
4
输出 #1复制
9
若两个数互质则能看到,题目转化为求1到n的欧拉函数的值

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int pri[100010],vis[100010],cnt,e[100010];
int main(){
    int n;
    cin>>n;
    e[1]=1;
    for(int i=2;i<=100000;i++){
        if(!vis[i]){
            pri[++cnt]=i;
            e[i]=i-1;
        }
        for(int j=1;j<=cnt,pri[j]*i<=100000;j++){
            vis[i*pri[j]]=1;
            if(i%pri[j]==0){
                e[i*pri[j]]=e[i]*pri[j];
                break;
            }
            else{
                e[i*pri[j]]=e[i]*e[pri[j]];
            }
        }
    }
    ll res=0;
    for(int i=1;i<n;i++)res+=e[i];
    if(n!=1)cout<<res*2+1<<endl;
    else cout<<0<<endl;
	return 0;
}

也可以用莫比乌斯反演做
在这里插入图片描述
P1865 A % B Problem
题目背景
题目名称是吸引你点进来的。
实际上该题还是很水的。

题目描述
给定 l, rl,r,求区间 [l, r][l,r] 内质数的个数。

输入格式
第一行有两个整数,分别代表询问次数 nn 和 给定区间的右端点最大值 mm。

接下来 nn 行,每行两个整数 l, rl,r,代表一次查询。

输出格式
对于每次查询输出一行,若 l, r \in [1, m]l,r∈[1,m],则输出区间质数个数,否则输出 Crossing the line。

输入输出样例
输入 #1复制
2 5
1 3
2 6
输出 #1复制
2
Crossing the line
将素数筛选出来,二分求解即可

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int pri[1000010],vis[1000010],cnt;
int main(){
    ios::sync_with_stdio(0);
    int l,r,m,n;
    cin>>n>>m;
    for(int i=2;i<=1e6;i++){
        if(!vis[i])pri[++cnt]=i;
        for(int j=1;j<=cnt,i*pri[j]<=1e6;j++){
            vis[i*pri[j]]=1;
            if(i%pri[j]==0){
                break;
            }
        }
    }
    //for(int i=1;i<=1000;i++)cout<<pri[i]<<endl;
    while(n--){
        cin>>l>>r;
        if(r>m||l<1)cout<<"Crossing the line\n";
        else{
            cout<<upper_bound(pri+1,pri+1+cnt,r)-lower_bound(pri+1,pri+1+cnt,l)<<endl;
        }



    }
	return 0;
}

P1835 素数密度
题目描述
给定区间 [L,R][L,R](1\leq L\leq R < 2^{31}1≤L≤R<2
31
,R-L\leq 10^6R−L≤10
6
),请计算区间中素数的个数。

输入格式
第一行,两个正整数 LL 和 RR。

输出格式
一行,一个整数,表示区间中素数的个数。

输入输出样例
输入 #1复制
2 11
输出 #1复制
5
只需将l到r中的合数剔除,将区间左移l,防止内存溢出

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e6+10;
long long pri[N],vis[N],cnt;
int main(){
    ios::sync_with_stdio(0);
    for(int i=2;i<=50000;i++){
        if(!vis[i])pri[++cnt]=i;
        for(int j=1;j<=cnt,i*pri[j]<=50000;j++){
            vis[i*pri[j]]=1;
            if(i%pri[j]==0)break;
        }
    }
    memset(vis,0,sizeof(vis));
    long long  l,r;
    cin>>l>>r;

    for(int i=1;i<=cnt;i++){
        //cout<<"   "<<i<<endl;
        long long j=(l%pri[i]?l-l%pri[i]+pri[i]:l);
        if(pri[i]<=r&&pri[i]>=l)j=2*pri[i];
        //cout<<pri[i]<<' '<<j<<endl;
        for(;j<=r;j+=pri[i]){
            //cout<<j<<endl;
            vis[j-l]=1;
        }
    }
    if(1==l)vis[0]=1;
    int res=0;
    for(int i=0;i<=r-l;i++){
        //cout<<i<<' '<<vis[i]<<endl;
        if(!vis[i])res++;
    }
    cout<<res<<endl;
	return 0;
}

P1463 [POI2001][HAOI2007]反素数
题目描述
对于任何正整数 xx,其约数的个数记作 g(x)g(x)。例如 g(1)=1g(1)=1,g(6)=4g(6)=4。

如果某个正整数 xx 满足:\forall 0 \lt i \lt x∀0<i<x,都有 g(x) \gt g(i)g(x)>g(i),则称 xx 为反质数。例如,整数 1,2,4,61,2,4,6 等都是反质数。

现在给定一个数 NN,你能求出不超过 NN 的最大的反质数么?

输入格式
一个数 NN。

输出格式
不超过 NN 的最大的反质数。

输入输出样例
输入 #1复制
1000
输出 #1复制
840

只需将前十几个素数存起来,按照每个质因数的幂次递减搜索。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int M=0x7fffffff;
int pri[200],vis[200],cnt,maxpo;
int res,n;
void dfs(int totpo,int now,int i){
    if(maxpo<totpo||(maxpo==totpo&&res>now)){
        res=now;
        maxpo=totpo;
    }

    //cout<<i<<' '<<now<<' '<<totpo<<' '<<res<<endl;
    if(i>10)return ;
    for(int j=1;j<=10;j++){
        if(now*pri[i]>n)break;
        dfs(totpo*(j+1),now*pri[i],i+1);
        now*=pri[i];
    }


}

signed main(){
    ios::sync_with_stdio(0);
    cin>>n;
    for(int i=2;i<=100;i++){

        if(!vis[i])pri[++cnt]=i;
        for(int j=1;j<=cnt,i*pri[j]<=100;j++){
            vis[i*pri[j]]=1;
            if(i%pri[j]==0)break;
        }
    }
    //for(int i=1;i<=10;i++)cout<<pri[i]<<endl;
    dfs(1,1,1);
    cout<<res;

	return 0;
}

P2261 [CQOI2007]余数求和
题目描述
给出正整数 nn 和 kk,请计算

G(n, k) = \sum_{i = 1}^n k \bmod i
G(n,k)=
i=1

n

kmodi

其中 k\bmod ikmodi 表示 kk 除以 ii 的余数。

输入格式
输入只有一行两个整数,分别表示 nn 和 kk。

输出格式
输出一行一个整数表示答案。

输入输出样例
输入 #1复制
10 5
输出 #1复制
29
在这里插入图片描述

在这里插入图片描述
然后利用数论分块降低复杂度。
分块:例如5/3和5/4和5/5都等于1,故可以当作一个区间,区间右端点为5/(5/3)=5

#include<bits/stdc++.h>
using namespace std;
#define ll long long

int main(){
    ios::sync_with_stdio(0);
    ll n,k;
    cin>>n>>k;
    ll res=0;
    for(ll i=1,j;i<=n;i=j+1){
        if(k>i)j=min(k/(k/i),n);
        else j=n;
        //cout<<i<< ' '<<j<<endl;
        res-=(j-i+1)*(k/i)*(i+j)/2;
        //cout<<i<<endl;
    }
    cout<<res+n*k;
	return 0;
}

P4626 一道水题 II
题目描述
一天,szb 在上学的路上遇到了灰太狼。

灰太狼:帮我们做出这道题就放了你。
szb:什么题?
灰太狼:求一个能被 [1,n][1,n] 内所有数整除的最小数字,并对 100000007100000007 取模。
szb:这题太水了,就让我小弟来做好了。

然后你就光荣的接受了这个任务。

输入格式
一行一个数 nn。

输出格式
一行一个数 ansans。

输入输出样例
输入 #1复制
10
输出 #1复制
2520
只需要枚举出质因子的最大的指数,然后相乘取模

#include<bits/stdc++.h>
using namespace std;
int n,pri[20000000],cnt;
bool vis[100000001];
int main(){
    ios::sync_with_stdio(0);
    long long res=1;
    cin>>n;
    for(long long i=2;i<=n;i++){
        if(!vis[i]){
            pri[++cnt]=i;
            long long x=i;
            while(x<n){
                x*=i;
            }
            res*=x/i;
            if(res>100000007)res%=100000007;
        }
        for(int j=1;j<=cnt,i*pri[j]<=n;j++){
            vis[i*pri[j]]=1;
            if(i%pri[j]==0)break;
        }

    }
    cout<<res;
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值