目录
A
算法提高 找素数
B
算法训练 区间k大数查询
C
算法训练 操作格子
D
算法提高 士兵排队问题
E
基础练习 十六进制转八进制
F
算法训练 最大最小公倍数
G
算法提高 欧拉函数
H
算法训练 乘法次数
I
算法训练 方格取数
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
#include
#include
#include
#include
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
B |
算法训练 区间k大数查询 |
时间限制: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
#include
#include
#include
#include
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;
}
C |
算法训练 操作格子 |
资源限制
时间限制: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
#include
#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>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<
D |
算法提高 士兵排队问题 |
资源限制
时间限制: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
#include
#include
#include
#include
#include
#include
typedef long long ll;
using namespace std;
const int N = 300;
int in[N];
vector v[N];
vector 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 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
E |
基础练习 十六进制转八进制 |
资源限制
时间限制: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
#include
#include
#include
using namespace std;
const int N = 100000 + 10;
char num[N];
int main()
{
int n;
cin>>n;
for(int i=0; i
F |
算法训练 最大最小公倍数 |
资源限制
时间限制: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
#include
#include
G |
算法提高 欧拉函数 |
资源限制
时间限制: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
#include
#include
H |
算法训练 乘法次数 |
资源限制
时间限制:1.0s 内存限制:999.4MB
问题描述
给你一个非零整数,让你求这个数的n次方,每次相乘的结果可以在后面使用,求至少需要多少次乘。如24:2*2=22(第一次乘),22*22=24(第二次乘),所以最少共2次;
输入格式
第一行m表示有m(1<=m<=100)组测试数据; 输出格式 输出每组测试数据所需次数s; 样例输入 3 样例输出 1 用到的算法:快速幂 思路:明显可以看出,求出n次幂的最快方法应该是不断累乘,即2^4 * 2^4,2^8 * 2^8,尽快求出n的二进制最高位的2^poww,再乘以已经算出过的低位即可. 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 思路:四维DP,两个人同时走. 时间限制:1.0s 内存限制:256.0MB资源限制 问题描述 对于长度为5位的一个01串,每一位都可能是0或1,一共有32种可能。它们的前几个是: 00000 00001 00010 00011 00100 请按从小到大的顺序输出这32种01串。 输入格式 本试题没有输入。 输出格式 输出32行,按从小到大的顺序每行一个长度为5的01串。 样例输出 00000 部分题解代码来自:https://blog.nowcoder.net/n/09f531a212f54db98f1aceee72468bfb?tdsourcetag=s_pctim_aiomsg
每一组测试数据有一整数n(0
2
3
4
2
2#include
I
算法训练 方格取数
设有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#include
00001
00010
00011
<以下部分省略>#include