第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 ", anss[n]); } return 0; }
#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 ", 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-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 ",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 "); else if (a>d||c>b) printf("0/1 "); 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 ",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 ",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 ",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 ",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 ",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 ",ans); } } return 0; }