赞
踩
目录
A | 算法提高 找素数 |
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
给定区间[L, R] , 请计算区间中素数的个数。
输入格式
两个数L和R。
输出格式
一行,区间中素数的个数。
样例输入
2 11
样例输出
5
数据规模和约定
2 <= L <= R <= 2147483647 R-L <= 1000000
思路:数据范围过大.普通的素数打表肯定是不行的,注意使用R-L <= 1000000这个条件,对sqrt(R)以内的素数进行打表,筛出L到R中素数的倍数(即合数),保存和数-L的状态,遍历得到结果.
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<cmath>
- #include<algorithm>
- typedef long long ll;
-
- using namespace std;
-
- const int N = 1000000 + 10;
-
- int prime[N];
- int num[N];
- int ans[N];
- int cnt=0;
-
- void prim(int n)
- {
- for(int i=2; i<=n; i++)
- {
- if(!prime[i])
- {
- num[cnt++] = i;
- for(int j=i*2; j<=n; j+=i)
- {
- prime[j] = 1;
- }
- }
- }
- }
-
-
- int main()
- {
- int l,r;
- cin>>l>>r;
- prim((int)sqrt(r));
- for(int i=0; i<cnt; i++)
- {
- int a = num[i];
- for(ll j=(l+a-1)/a*a; j<=r; j+=a)//注意减1,否则容易漏掉l-l+a中a的倍数.
- {
- if(j == a) continue;
- else ans[j-l] = 1;
- }
- }
- int cnt = 0;
- for(int i=0; i<=r-l; i++)
- {
- if(ans[i] == 0) cnt++;
- }
- cout<<cnt;
- return 0;
- }

时间限制:1.0s 内存限制:256.0MB
问题描述
给定一个序列,每次询问序列中第l个数到第r个数中第K大的数是哪个。
输入格式
第一行包含一个数n,表示序列长度。
第二行包含n个正整数,表示给定的序列。
第三个包含一个正整数m,表示询问个数。
接下来m行,每行三个数l,r,K,表示询问序列从左往右第l个数到第r个数中,从大往小第K大的数是哪个。序列元素从1开始标号。
输出格式
总共输出m行,每行一个数,表示询问的答案。
样例输入
5
1 2 3 4 5
2
1 5 2
2 3 2
样例输出
4
2
数据规模与约定
对于30%的数据,n,m<=100;
对于100%的数据,n,m<=1000;
保证k<=(r-l+1),序列中的数<=106。
思路:把原数组L-R复制到处理数组中,从大到小进行排序,输出第K个.
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<cmath>
- #include<algorithm>
- typedef long long ll;
-
- using namespace std;
-
- const int N = 1000000 + 10;
-
- int ans;
-
- int num[N];
- int temp[N];
- bool cmp(int a, int b)
- {
- return a > b;
- }
- int main()
- {
- int n,m;
- cin>>n;
- for(int i=1; i<=n; i++)
- scanf("%d",&num[i]);
- cin>>m;
- int l,r,k;
- while(m--)
- {
- scanf("%d %d %d",&l,&r,&k);
- int cnt=1;
- for(int i=l; i<=r; i++)
- temp[cnt++] = num[i];
- sort(temp + 1, temp + cnt, cmp);
- printf("%d\n",temp[k]);
- }
- return 0;
- }

资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
有n个格子,从左到右放成一排,编号为1-n。
共有m次操作,有3种操作类型:
1.修改一个格子的权值,
2.求连续一段格子权值和,
3.求连续一段格子的最大值。
对于每个2、3操作输出你所求出的结果。
输入格式
第一行2个整数n,m。
接下来一行n个整数表示n个格子的初始权值。
接下来m行,每行3个整数p,x,y,p表示操作类型,p=1时表示修改格子x的权值为y,p=2时表示求区间[x,y]内格子权值和,p=3时表示求区间[x,y]内格子最大的权值。
输出格式
有若干行,行数等于p=2或3的操作总数。
每行1个整数,对应了每个p=2或3操作的结果。
样例输入
4 3
1 2 3 4
2 1 3
1 4 3
3 1 4
样例输出
6
3
数据规模与约定
对于20%的数据n <= 100,m <= 200。
对于50%的数据n <= 5000,m <= 5000。
对于100%的数据1 <= n <= 100000,m <= 100000,0 <= 格子权值 <= 10000。
思路:线段树模板题,需要同时维护一个maxn值和一个sum值.
- #include<iostream>
- #include<climits>
- #define ll long long
- using namespace std;
-
- const int N = 1e5 + 10;
- int n,m;
-
- struct node{
- int l,r;
- int maxn;
- int sum;
- }tree[4*N];
-
- int num[N];
-
- void build(int u,int l,int r)
- {
- if(l == r)
- {
- tree[u] = {l,r,num[r],num[r]};
- }
- else
- {
- int mid = (r + l) >> 1;
- build(u << 1, l, mid);
- build(u << 1 | 1, mid + 1, r);
- tree[u] = {l,r};
- tree[u].maxn = max(tree[u << 1].maxn, tree[u << 1 | 1].maxn);
- tree[u].sum = tree[u << 1].sum + tree[u << 1 | 1].sum;
- }
- }
-
- int query1(int u, int l ,int r)
- {
- if(tree[u].l >= l && tree[u].r <= r) return tree[u].maxn;
- int maxnn = INT_MIN;
- int mid = (tree[u].l + tree[u].r) >> 1;
- if(mid >= l) maxnn = query1(u << 1, l, r);
- if(mid < r) maxnn = max(maxnn, query1(u << 1 | 1, l, r));
- return maxnn;
- }
-
- int query2(int u, int l ,int r)
- {
- if(tree[u].l >= l && tree[u].r <= r) return tree[u].sum;
- int sum = 0;
- int mid = (tree[u].l + tree[u].r) >> 1;
- if(mid >= l) sum = query2(u << 1, l, r);
- if(mid < r) sum += query2(u << 1 | 1, l, r);
- return sum;
- }
-
- void modify(int u, int x, int v)
- {
- if(tree[u].l == tree[u].r)
- {
- tree[u].maxn = v;
- tree[u].sum = v;
- }
- else
- {
- int mid =(tree[u].l + tree[u].r) >> 1;
- if(x <= mid) modify(u << 1, x, v);
- else modify(u << 1 | 1,x,v);
- tree[u].sum = tree[u << 1].sum + tree[u << 1 | 1].sum;
- tree[u].maxn = max(tree[u << 1].maxn, tree[u << 1 | 1].maxn);
- }
- }
- int main()
- {
- cin>>n>>m;
- for(int i=1; i<=n; i++)
- {
- scanf("%d",&num[i]);
- }
- build(1,1,n);
- for(int i=0; i<m; i++)
- {
- int opt;
- cin>>opt;
- if(opt == 1)
- {
- int x, y;
- cin>>x>>y;
- modify(1,x,y);
- }
- else if(opt == 2)
- {
- int l,r;
- cin>>l>>r;
- printf("%lld\n",query2(1,l,r));
- }
- else if(opt == 3)
- {
- int l,r;
- cin>>l>>r;
- cout<<query1(1,l,r)<<endl;
- }
- }
- return 0;
- }

资源限制
时间限制:1.0s 内存限制:256.0MB
试题
有N个士兵(1≤N≤26),编号依次为A,B,C,…,队列训练时,指挥官要把一些士兵从高到矮一次排成一行,但现在指挥官不能直接获得每个人的身高信息,只能获得“P1比P2高”这样的比较结果(P1、P2∈A,B,C,…,Z,记为 P1>P2),如”A>B”表示A比B高。
请编一程序,根据所得到的比较结果求出一种符合条件的排队方案。
(注:比较结果中没有涉及的士兵不参加排队)
输入要求
比较结果从文本文件中读入(文件由键盘输入),每个比较结果在文本文件中占一行。
输出要求
若输入数据无解,打印“No Answer!”信息,否则从高到矮一次输出每一个士兵的编号,中间无分割符,并把结果写入文本文件中,文件由键盘输入:
样例输入
A>B
B>D
F>D
样例输出
AFBD
思路:拓扑排序模板题,判断有没有环,无环即可.
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<cmath>
- #include<algorithm>
- #include<queue>
- #include<vector>
- typedef long long ll;
-
- using namespace std;
-
- const int N = 300;
-
- int in[N];
- vector <char> v[N];
- vector <char> ans;
- bool st[N];
-
- int main()
- {
- freopen("in.txt","r",stdin);
- freopen("out.txt","w",stdout);
- char c[4];
- while(~scanf("%s",c+1))
- {
- char x = c[1];
- char y = c[3];
- v[x].push_back(y);
- in[y]++;
- st[x]=st[y]=1;
- }
- queue<char> q;
- int total = 0;
- for(int i='A'; i<='Z'; i++)
- {
- if(in[i] == 0 && st[i] == 1)
- {
- q.push(i);
- }
- if(st[i] == 1) total++;
- }
- while(!q.empty())
- {
- char tem = q.front();
- total--;
- ans.push_back(tem);
- q.pop();
- for(int i=0; i<v[tem].size(); i++)
- {
- in[v[tem][i]]--;
- if(in[v[tem][i]] == 0) q.push(v[tem][i]);
- }
- }
- if(total == 0)
- {
- for(int i=0; i<ans.size(); i++)
- cout<<ans[i];
- }
- else puts("No Answer!");
- return 0;
- }

资源限制
时间限制:1.0s 内存限制:512.0MB
问题描述
给定n个十六进制正整数,输出它们对应的八进制数。
输入格式
输入的第一行为一个正整数n (1<=n<=10)。
接下来n行,每行一个由0~9、大写字母A~F组成的字符串,表示要转换的十六进制正整数,每个十六进制数长度不超过100000。
输出格式
输出n行,每行为输入对应的八进制正整数。
【注意】
输入的十六进制数不会有前导0,比如012A。
输出的八进制数也不能有前导0。
样例输入
2
39
123ABC
样例输出
71
4435274
【提示】
先将十六进制数转换成某进制数,再由某进制数转换成八进制。
思路:利用sscanf的16进制读取功能每六位读取一次,再利用printf的8进制的输出功能输出,注意对不足六位的16进制数及转化后不足八位的16进制数进行特殊处理.
- #include<iostream>
- #include<algorithm>
- #include<cstring>
- #include<cstdio>
- using namespace std;
-
- const int N = 100000 + 10;
-
- char num[N];
-
- int main()
- {
- int n;
- cin>>n;
- for(int i=0; i<n; i++)
- {
- scanf("%s",num);
- int len = strlen(num);
- int x;
- if(len % 6)//如果16进制数不能刚好分成多个8位8进制数,则在开头对多出来的部分特殊处理
- {
- switch(len % 6)
- {
- case 1:
- sscanf(num,"%1x",&x);
- printf("%o",x);
- break;//别忘了break
- case 2:
- sscanf(num,"%2x",&x);
- printf("%o",x);
- break;
- case 3:
- sscanf(num,"%3x",&x);
- printf("%o",x);
- break;
- case 4:
- sscanf(num,"%4x",&x);
- printf("%o",x);
- break;
- case 5:
- sscanf(num,"%5x",&x);
- printf("%o",x);
- break;
- }
- }
- int j = len % 6;
- while(j < len)
- {
- sscanf(num+j,"%6x",&x);
- if(j==0) printf("%o",x);
- else printf("%08o",x); //在16进制数的开头之后可能有6位数太小,转化成8进制数不足8位,需要在不足的位置添0
- j+=6;
- }
- puts("");
- }
- return 0;
- }

资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
已知一个正整数N,问从1~N中任选出三个数,他们的最小公倍数最大可以为多少。
输入格式
输入一个正整数N。
输出格式
输出一个整数,表示你找到的最小公倍数。
样例输入
9
样例输出
504
数据规模与约定
1 <= N <= 106。
思路:这题的关键在与只选取3个数,我们知道如果只选择两个数的话,那么肯定选两个相邻的两数,因为他两互质所以最小公倍数是最大的。所以面对要选择三个数,我们也可以设法选出3个互质的数。对于相邻的a,b,c三个数有奇偶奇,偶奇偶,可以发现奇偶奇三个数一定是互质的,a与b互质,b与c互质,a与b之间不可有共因子2,|c-a|<3,所以也不可能存在共因子3,之后的更别说了。
然后是偶奇偶,其最大最小公倍数必定至少除2,所以可以尝试把其中一个偶换成奇数,且不构成3的倍数,或者整体-1,变成奇偶奇。
- #include <iostream>
- #include <algorithm>
- #include <map>
- #include <string>
- #include <queue>
- #include <vector>
- using namespace std;
- const int maxn = 300;
- typedef pair<int,int> pii;
- typedef long long ll;
-
- ll N;
- int main(){
- cin>>N;
- ll mx = 0;
- if(N<3) mx = N;
- else if(N&1){ //奇偶奇
- mx = N*(N-1)*(N-2);
- }else{
- if(N%3 !=0){ //N和N-3不是3的倍数
- mx = N*(N-1)*(N-3);
- }else{ //整体-1
- mx = (N-1)*(N-2)*(N-3);
- }
- }
- cout<<mx<<endl;
- return 0;
- }

资源限制
时间限制:1.0s 内存限制:512.0MB
说明
2016.4.5 已更新试题,请重新提交自己的程序。
问题描述
给定一个大于1,不超过2000000的正整数n,输出欧拉函数,phi(n)的值。
如果你并不了解欧拉函数,那么请参阅提示。
输入格式
在给定的输入文件中进行读入:
一行一个正整数n。
输出格式
将输出信息输出到指定的文件中:
一行一个整数表示phi(n)。
样例输入
17
样例输出
16
提示
欧拉函数phi(n)是数论中非常重要的一个函数,其表示1到n-1之间,与n互质的数的个数。显然的,我们可以通过定义直接计算phi(n)。
当然,phi(n)还有这么一种计算方法。
首先我们对n进行质因数分解,不妨设n=p1^a1 * p2^a2 * ... * pk^ak (这里a^b表示a的b次幂,p1到pk为k个互不相同的质数,a1到ak均为正整数),那么
phi(n)=n(1-(1/p1))(1-(1/p2))....(1-(1/pk))
稍稍化简一下就是
phi(n)=n(p1-1)(p2-1)...(pk-1)/(p1*p2*...*pk)
计算的时候小心中间计算结果超过int类型上界,可通过调整公式各项的计算顺序避免(比如先做除法)!
用到的算法:欧拉筛
线性复杂度,把前maxn个数的欧拉值筛选出来
- #include <iostream>
- #include <algorithm>
- #include <map>
- #include <string>
- #include <queue>
- #include <vector>
- using namespace std;
- const int maxn = 2e6+10;
- typedef pair<int,int> pii;
- typedef long long ll;
-
- ll N;
- int E[maxn];
- void init()
- {
- E[1] = 1;
- for(int i=2;i<maxn;i++){
- if(!E[i])
- for(int j=i;j<maxn;j+=i){
- if(!E[j]) E[j]=j;
- E[j] = E[j]/i*(i-1);
- }
- }
- }
- int main(){
- init();
- cin>>N;
- cout<<E[N]<<endl;
- return 0;
- }

资源限制
时间限制:1.0s 内存限制:999.4MB
问题描述
给你一个非零整数,让你求这个数的n次方,每次相乘的结果可以在后面使用,求至少需要多少次乘。如24:2*2=22(第一次乘),22*22=24(第二次乘),所以最少共2次;
输入格式
第一行m表示有m(1<=m<=100)组测试数据;
每一组测试数据有一整数n(0<n<=100000000);
输出格式
输出每组测试数据所需次数s;
样例输入
3
2
3
4
样例输出
1
2
2
用到的算法:快速幂
思路:明显可以看出,求出n次幂的最快方法应该是不断累乘,即2^4 * 2^4,2^8 * 2^8,尽快求出n的二进制最高位的2^poww,再乘以已经算出过的低位即可.
- #include <iostream>
- #include <cmath>
- using namespace std;
- typedef long long ll;
- const ll mod = 1000000007;
- int T;
- ll ksm(ll a,ll b){
- int poww = 0,cnt = 0;
- while(b){
- if(b&1) {
- cnt += 1;
- }
- a = a*a% mod;// 也可以不写
- poww++;
- b>>=1;
- }
- return poww+cnt-2;
- }
- int main(){
- cin>>T;
- while(T--){
- ll b;scanf("%lld",&b);
- printf("%lld\n",ksm(2,b));
- }
-
- return 0;
- }

资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
设有N*N的方格图(N<=10),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0。
某人从图的左上角的A 点(1,1)出发,可以向下行走,也可以向右走,直到到达右下角的B点(N,N)。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。
此人从A点到B 点共走两次,试找出2条这样的路径,使得取得的数之和为最大。
输入格式
输入的第一行为一个整数N(表示N*N的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的0表示输入结束。
输出格式
只需输出一个整数,表示2条路径上取得的最大的和。
样例输入
8
2 3 13
2 6 6
3 5 7
4 4 14
5 2 21
5 6 4
6 3 15
7 2 14
0 0 0
样例输出
67
思路:四维DP,两个人同时走.
- #include<iostream>
- #include<map>
- #include<cmath>
- using namespace std;
-
- const int N = 11;
-
- int val[N][N];
- int dp[N][N][N][N];
-
- int main()
- {
- int n;
- cin>>n;
- int x,y,z;
- while(cin>>x>>y>>z&&x&&y&&z)
- {
- val[x][y] = z;
- }
- dp[1][1][1][1] = val[1][1];
- for(int x1=1; x1<=n; x1++)
- {
- for(int y1=1; y1<=n; y1++)
- {
- for(int x2=1; x2<=n; x2++)
- {
- for(int y2=1; y2<=n; y2++)
- {
- if(x1+y1 != x2+y2) continue;
- int tem = 0;
- tem = max(dp[x1-1][y1][x2-1][y2],dp[x1-1][y1][x2][y2-1]);
- tem = max(dp[x1][y1-1][x2-1][y2], tem);
- tem = max(dp[x1][y1-1][x2][y2-1], tem);
- dp[x1][y1][x2][y2] = tem + val[x1][y1] + val[x2][y2];
- if(x1 == x2 && y1 == y2) dp[x1][y1][x2][y2] -=val[x1][y1];
- }
- }
- }
- }
- cout<<dp[n][n][n][n];
- return 0;
- }
-
-
- //8
- //2 3 13
- //2 6 6
- //3 5 7
- //4 4 14
- //5 2 21
- //5 6 4
- //6 3 15
- //7 2 14
- //0 0 0

时间限制:1.0s 内存限制:256.0MB资源限制
问题描述
对于长度为5位的一个01串,每一位都可能是0或1,一共有32种可能。它们的前几个是:
00000
00001
00010
00011
00100
请按从小到大的顺序输出这32种01串。
输入格式
本试题没有输入。
输出格式
输出32行,按从小到大的顺序每行一个长度为5的01串。
样例输出
00000
00001
00010
00011
<以下部分省略>
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<cmath>
- #include<algorithm>
- typedef long long ll;
-
- using namespace std;
-
- int num[100];
-
- int main()
- {
- for(int i=0; i<32; i++)
- {
- int cnt=0;
- int j=i;
- while(j)
- {
- num[cnt++] = j % 2;
- j = j/2;
- }
- for(int k=4; k>=0; k--)
- cout<<num[k];
- puts("");
- }
- }

部分题解代码来自:https://blog.nowcoder.net/n/09f531a212f54db98f1aceee72468bfb?tdsourcetag=s_pctim_aiomsg
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。