2019CSUST选拔赛

 第1题

此题是一个关于数论素数筛的问题,同时由于多组输入的数组十分庞大,所以简单的暴力查找是会超时的,尽管用了前缀和,也还是会超时,所以我们在这里用数组数组(或者线段树)储存每一次找到某个数的最小素因子时,小于等于该数的最小素因子并且其数的大小小于该数的值:

代码如下:

#include <bits/stdc++.h>
using namespace std;
#define MAX_N 1000005
#define MIN(a,b) (a) > (b) ? (b):(a)
int vis[MAX_N + 5] = {0};
int anss[MAX_N + 5] = {0};
int  sum[MAX_N+5];
int lowbit(int  x) {
    return x&-x;
}
void update(int point,int d) {
    while(point<=MAX_N) {
        sum[point]+=d;
        point+=lowbit(point);
    }
    return ;
}
int qiuhe(int point) {
    int ans=0;
    while(point>0) {
        ans+=sum[point];
        point-=lowbit(point);
    }
    return ans;
}
void init() {
    for(int i=2; i<=MAX_N; i++) {
        if (vis[i])
            continue;
        for(int k=i; k<=MAX_N; k+=i) {
            if (vis[k]) 
                continue;
            anss[k]=qiuhe(k);
            vis[k]=1;
            update(k,1);
        }
    }
}
int main() {
    int n;
    update(1,1);
    init();
    int t;
    scanf("%d",&t);
    while (t--) {
        int n;
        scanf("%d",&n);
        printf("%d\n", anss[n]);
    }
    return 0;
}
View Code
#include <bits/stdc++.h>
using namespace std;
#define MAX_N 1000005
#define MIN(a,b) (a) > (b) ? (b):(a)
int vis[MAX_N + 5] = {0};
int anss[MAX_N + 5] = {0};
int  sum[MAX_N+5];
int lowbit(int  x) {
    return x&-x;
}
void update(int point,int d) {
    while(point<=MAX_N) {
        sum[point]+=d;
        point+=lowbit(point);
    }
    return ;
}
int qiuhe(int point) {
    int ans=0;
    while(point>0) {
        ans+=sum[point];
        point-=lowbit(point);
    }
    return ans;
}
void init() {
    for(int i=2; i<=MAX_N; i++) {
        if (vis[i])
            continue;
        for(int k=i; k<=MAX_N; k+=i) {
            if (vis[k]) 
                continue;
            anss[k]=qiuhe(k);
            vis[k]=1;
            update(k,1);
        }
    }
}
int main() {
    int n;
    update(1,1);
    init();
    int t;
    scanf("%d",&t);
    while (t--) {
        int n;
        scanf("%d",&n);
        printf("%d\n", anss[n]);
    }
    return 0;
}

第二题:

此题我们采用并查集的思路,将提莫种了蘑菇的道路不予连接,因为题目保证输入之后构成一棵树,这样处理之后,由于缺少路径,就会导致形成一片森林。而我们通过计算每一棵树的连通路径 便可以求出不连通的路径了 。

代码如下:

#include <bits/stdc++.h>
using namespace std;
#define  maxn 300005
int par[maxn];
int rak[maxn];
bool t[maxn]= {0};
long long n;
long long  zhi[maxn]= {0};
void init() {
    for(int i=1; i<=n; i++) {
        par[i]=i;
        rak[i]=0;
    }
}
int fid(int x) {
    if (par[x]==x)
        return x;
    else
        return par[x]=fid(par[x]);
}
void join(int x,int y) {
    x=fid(x);
    y=fid(y);
    if (x==y)
        return;
    if (rak[x]<rak[y])
        par[x]=par[y];
    else {
        par[y]=par[x];
        if (rak[x]==rak[y])
            rak[x]++;
    }
}
int main() {
    scanf("%lld",&n);
    init();
    int a,b,c;
    for(int i=1; i<n; i++) {
        scanf("%d%d%d",&a,&b,&c);
        if (c==0)
            join(a,b);
    }
    long long ans=0;
    for(int i=1; i<=n; i++) {
        zhi[fid(i)]++; 
    }
    for(int i=1; i<=n; i++)
        if(zhi[i]>1)
            ans+=zhi[i]*(zhi[i]-1);
    printf("%lld\n",n*(n-1)-ans);
    return 0;
}

  第三题:

此题是一道LCA求树上2点之间的距离 但由于加了一条边,所以我们需要判断一下究竟加的那条边对于我们所要求的结果有没有影响。

代码如下:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#include <string>
#include <cmath>
using namespace std;
#define Maxn 100010
#define Maxm 21
struct Edge {
    int to,val;
    Edge() {}
    Edge(int a,int b) {
        to = a;
        val = b;
    }
};
vector<Edge> adj[Maxn];//用来存树
int dep[Maxn];//深度
int dis[Maxn];//节点到根节点的距离
int gra[Maxn][Maxm];//节点i的第2^j的祖先
int n,m;
int root;
void Init() {
    scanf("%d",&n);
    m = floor(log(n+0.0) / log(2.0));
    int x,y,z;
    for(int i=1; i<n; i++) {
        scanf("%d%d%d",&x,&y,&z);
        adj[x].push_back(Edge(y,z));
        adj[y].push_back(Edge(x,z));
    }
    root = 1;
    dep[root] = 1;
    dis[root] = 0;

    dep[0] = -1;
}

void dfs(int u,int pre) {
    for(int i=1; i<=m; i++) {
        gra[u][i] = gra[gra[u][i-1]][i-1];
        if(!gra[u][i])
            break;
    }

    int len = adj[u].size();
    for(int i=0; i<len; i++) {
        Edge e = adj[u][i];
        if(e.to != gra[u][0]) {
            dis[e.to] = dis[u] + e.val;
            dep[e.to] = dep[u] + 1;
            gra[e.to][0] = u;
            dfs(e.to,u);
        }
    }
}

int LCA(int x,int y) {
    if(dep[x] > dep[y])
        swap(x,y);

    for(int i=m; i>=0; i--)
        if(dep[gra[y][i]] >= dep[x])
            y = gra[y][i];
    for(int i=m; i>=0; i--)
        if(gra[x][i] != gra[y][i])
            x = gra[x][i],y = gra[y][i];

    if(x!=y)
        x = gra[x][0];
    return x;
}

int main() {
    Init();
    dfs(root,-1);
    int jiax,jiay,jiaz;
    scanf("%d%d%d",&jiax,&jiay,&jiaz);
    int q,x,y,lca,lca0;
    scanf("%d",&q);
    while(q--) {
        scanf("%d%d",&x,&y);
            lca=LCA(x,y);
            lca0=(dis[x] + dis[y]-2 *dis[lca]);
            int  lca1=dis[x]+dis[jiax]-2*dis[LCA(x,jiax)];
            int  lca2=dis[y]+dis[jiay]-2*dis[LCA(y,jiay)];
            int  lca3=dis[x]+dis[jiay]-2*dis[LCA(x,jiay)];
            int  lca4=dis[y]+dis[jiax]-2*dis[LCA(y,jiax)];
            printf("%d\n",min(lca0,min(lca1+lca2+jiaz,lca3+lca4+jiaz)));
    }
    return 0;
}

第4题:

此题就是一个小小的对数据处理就行,尤其注意a或者c为0的情况,注意题目数据范围即可

代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
long long gcdd(long long a,long long b)
{
    return b==0?a:gcdd(b,a%b);
}
int main() {
    int t;
    scanf("%d",&t);
    while(t--) {
        long long  a,b,c,d;
        scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
        if ((a==b&&a==0)||(c==d&&d==0))
            printf("0/1\n");
        else if (a>d||c>b)
            printf("0/1\n");
        else {
            if (a==0)
                a=1;
            if (c==0)
                c=1;
            long long ans;
            if (c>=a)
                ans=min(b-c+1,min(b-a+1,d-c+1));
            else 
                ans=min(d-a+1,min(b-a+1,d-c+1));
            long long sum=(b-a+1)*(d-c+1);
            long long ss=gcdd(sum,ans);
            printf("%lld/%lld\n",ans/ss,sum/ss);
                
        }
    }
    return 0;
}

第5题:

此题就是一个贪心的问题 对于没次输入,按从小到大排序,然后从最小的依次运算即可

#include <bits/stdc++.h>
using namespace std;
#define ll long long 
ll a[105][10];
int main() {
    int n,k;
    cin>>n>>k;
    for(int i=0;i<n;i++) {
        for(int j=0;j<k;j++) {
            cin>>a[i][j];
        }
        sort(a[i],a[i]+k);
    }
    long long ans=0;
    for(int j=0;j<k;j++) {
        for(int i=1;i<n;i++) {
            ans += abs(a[i][j]-a[i-1][j]);
        }
    }
    cout<<ans<<endl;
    return 0;
}

第6题:

 

 

此题就是一个最短路的问题,我们跑n次最短路,然后找出最小的即可 这里我用的是dij+优先队列的最短路。

代码如下:

#include <bits/stdc++.h>
using namespace std;
const long long  maxn=1010,INF=1e11;
long long dis[maxn];
bool vis[maxn];
struct node {
    int to,len;
    node(int to,int len):to(to),len(len) {} //方便插入vector
    bool operator<(const node& a)const {
        return len>a.len;   //用于优先队列排序,从小到大排
    }
};
int n,m;
vector<node>Map[maxn];
long long  Dijkstra(int s) {
    for(int i=1; i<=n; i++)
        dis[i]=INF;
    memset(vis,0,sizeof(vis));
    dis[s]=0;
    priority_queue<node>Q;
    Q.push(node(s,0));
    while(!Q.empty()) {
        node u=Q.top();
        Q.pop();
        if(vis[u.to])
            continue;
        vis[u.to]=1;
        for(int i=0; i<Map[u.to].size(); i++) {
            node v=Map[u.to][i];
            if(dis[v.to]>dis[u.to]+v.len) {
                dis[v.to]=dis[u.to]+v.len;
                Q.push(node(v.to,dis[v.to]));
            }
        }
    }
    long long ans=0;
    for(int i=1; i<=n; i++)
        ans+=dis[i];
    return ans;
}
int main() {
    while(scanf("%d%d",&n,&m)!=EOF) {
        for(int i=0; i<=n; i++)
            Map[i].clear();
        for(int i=0; i<m; i++) {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            Map[a].push_back(node(b,c));
            Map[b].push_back(node(a,c));
        }
        long long min1=Dijkstra(1);
        int gg;
        for(int i=2; i<=n; i++) {
            if (Dijkstra(i)<min1) {
                min1=Dijkstra(i);
                gg=i;
            }
        }
        printf("%lld %d\n",min1,gg);
    }
    return 0;
}

第7题:

次题就是一个求逆序和的题。

代码如下:

#include <bits/stdc++.h>
using namespace std;
#define maxn 100005
int n,t;
long long ans,temp;
int yi[maxn],er[maxn],cha[maxn];
int swap_space[maxn];
void merge(int a[],int begin,int mid,int end) {
    int i=begin;
    int j=mid+1;
    int k=begin;
    while(i<=mid&&j<=end) {
        if(a[i]<a[j])
            swap_space[k++]=a[i++];
        else {
            swap_space[k++]=a[j++];
            ans+=(mid-i+1);
        }
    }
    while(i<=mid)
        swap_space[k++]=a[i++];
    while(j<=end)
        swap_space[k++]=a[j++];
    for(i=begin; i<=end; i++)
        a[i]=swap_space[i];
}

void mergeSort(int a[],int begin,int end) {
    if(begin!=end) {
        int mid=(begin+end)/2;
        mergeSort(a,begin,mid);
        mergeSort(a,mid+1,end);
        merge(a,begin,mid,end);
    }
}

int main() {
    scanf("%d",&t);
    while(t--) {
        memset(yi,0,sizeof(yi));
        memset(er,0,sizeof(er));
        memset(swap_space,0,sizeof(swap_space));
        memset(cha,0,sizeof(cha));
        ans=0;
        scanf("%d",&n);
        for(int i=1; i<=n; i++) {
            scanf("%lld",&temp);
            yi[temp]=i;
        }
        for(int i=1; i<=n; i++) {
            cha[i]=yi[i];
        }
        for(int i=1; i<=n; i++) {
            scanf("%lld",&temp);
            er[i]=cha[temp];
        }
        mergeSort(er,1,n);
        printf("%lld\n",ans);
    }
    return 0;
}

第8题

此题是一个二分的题目,对于给出的的函数,我们不难发现其中的单调性,所以二分目标结果即可,但由于时间限制,我们需要维护前缀合。

代码如下:

#include<bits/stdc++.h>
using namespace std;
#define maxn 200005
#define ll long long
ll w[maxn];
ll v[maxn];
ll re[maxn];
ll le[maxn];
ll ss[maxn];
ll nn[maxn];
ll ans=1e18;
int n,m;
ll s;
ll check(int  x) {
    long long sum=0;
    ss[0]=0;
    nn[0]=0;
    for(int i=1; i<=n; i++) {
        if(w[i]>=x) {
            ss[i]=ss[i-1]+v[i];
            nn[i]=nn[i-1]+1;
        } else {
            ss[i]=ss[i-1];
            nn[i]=nn[i-1];
        }
    }
    for(int i=0; i<m; i++) {
        sum+=(ss[re[i]]-ss[le[i]-1])*(nn[re[i]]-nn[le[i]-1]);
    }
    if(abs(sum-s)<ans) {
        ans=abs(sum-s);
    }
    return sum;
}
int main() {
    scanf("%d%d%lld",&n,&m,&s);
    for(int i=1; i<=n; i++) {
        scanf("%lld%lld",&w[i],&v[i]);
    }
    for(int i=0; i<m; i++) {
        scanf("%lld%lld",&le[i],&re[i]);
    }
    int left=0,right=1e7,mid;
    while(left<=right) {
        mid =(left+right)/2;
        if(check(mid)<s) {
            right=mid-1;
        } else {
            left=mid+1;
        }
    }
    check(left-1);
    check(left+1);
    printf("%lld\n",ans);
    return 0;
}

第9题:

此题是一个只有2个物品的完全背包问题,十分的简单,

#include <bits/stdc++.h>
using namespace std;
#define ll long long 
const long long  mod=1e8+7;
int   t;
long long  dp[500000];
int main() {
    scanf("%d",&t);
    while(t--)
    {
        memset(dp,0,sizeof(dp));
        dp[0]=1;
        int n,m;
        scanf("%d%d",&n,&m);
        int  w[2];
        w[0]=1;
        w[1]=m;
        for(int i=0;i<=n;i++)
        {
            for(int j=0;j<2;j++)
            {
                if (w[j]<=i) dp[i]=(dp[i]+dp[i-w[j]])%mod;
            }
        }
            printf("%lld\n",dp[n]);
    }
    return 0;
    
}

第10题:

此题就是一道线段树的模板题,包含区间修改,区间查询,单点修改等操作。

代码如下:

#include <bits/stdc++.h>
using namespace std;
long long n,q,a,b,m,x,y;
long long ans;
struct node {
    long long l,r;
    long long w,f;
} tree[4000005];
void build (long long k,long long ll,long long rr) {
    tree[k].l=ll,tree[k].r=rr;
    if(tree[k].l==tree[k].r) {
        scanf("%lld",&tree[k].w);
        return;
    }
    long long m=(ll+rr)/2;
    build(k*2,ll,m);
    build(k*2+1,m+1,rr);
    tree[k].w=tree[k*2].w+tree[k*2+1].w;
}
void down(long long k) {
    tree[k*2].f+=tree[k].f;
    tree[k*2+1].f+=tree[k].f ;
    tree[k*2].w+=tree[k].f*(tree[k*2].r-tree[k*2].l+1);
    tree[k*2+1].w+=tree[k].f*(tree[k*2+1].r-tree[k*2+1].l+1);
    tree[k].f=0;
}
void change_point(long long k) {
    if(tree[k].l==tree[k].r) {
        tree[k].w=y;
        return;
    }
    if(tree[k].f)
        down(k);
    long long m=(tree[k].l+tree[k].r)/2;
    if(x<=m)
        change_point(k*2);
    else
        change_point(k*2+1);
    tree[k].w=tree[k*2].w+tree[k*2+1].w;
}
void ask_interval(long long k) {
    if(tree[k].l>=a&&tree[k].r<=b) {
        ans+=tree[k].w;
        return;
    }
    if(tree[k].f)
        down(k);
    long long m=(tree[k].l+tree[k].r)/2;
    if(a<=m)
        ask_interval(k*2);
    if(b>m)
        ask_interval(k*2+1);
}
void change_interval(long long k) {
    if(tree[k].l>=a&&tree[k].r<=b) {
        tree[k].w+=(tree[k].r-tree[k].l+1)*y;
        tree[k].f+=y;
        return;
    }
    if(tree[k].f)
        down(k);
    long long m=(tree[k].l+tree[k].r)/2;
    if(a<=m)
        change_interval(k*2);
    if(b>m)
        change_interval(k*2+1);
    tree[k].w=tree[k*2].w+tree[k*2+1].w;
}


int main() {
    scanf("%lld%lld",&n,&q);
    build(1,1,n);
    while(q--) {
        char ss[10];
        scanf("%s",ss);
        if (ss[1]=='1') {
            scanf("%lld%lld%lld",&a,&b,&y);
            change_interval(1);
        }
        if (ss[1]=='2') {
            scanf("%lld%lld%lld",&a,&b,&y);
            y=-y;
            change_interval(1);
        }
        if (ss[1]=='3') {
            scanf("%lld%lld",&x,&y);
            change_point(1);
        }
        if (ss[1]=='4') {
            scanf("%lld%lld",&a,&b);
            ans=0;
            ask_interval(1);
            printf("%lld\n",ans);
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/ysl1311/p/10485965.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值