A: 区间or值
题目:
gbx从老板那里获得了一个长度为n的非负整数序列,以及老板的一个需求。老板要gbx写一个程序支持查询一个区间的or的结果。当老板给出一个区间[x,y]的时候,gbx就必须立刻告诉老板A[x] or A[x+1] or A[x+2] or … or A[y]的结果。
现在老板有m次询问,gbx觉得太烦,就要你来解决这个问题。
输入格式:
第一行一个整数T,表示数据的组数(1<=T<=5)
对于每组数据,首先读入两个整数n,m ( 1<=n,m<=10^5)表示序列长度和老板询问次数。
接下来一行读入n个非负整数,表示序列的数,每个数不超过10^9。
接下来m行,每行两个整数xi,yi,表示询问区间(1<=x<=y<=n)。
输出格式:
对于每次询问,输出一个整数,代表询问区间的or和。
输入样例:
1
6 3
1 2 3 4 5 6
1 3
3 5
2 4
输出样例:
3
7
7
注意:
or是二进制按位取或操作(符号是一个竖线|)。4 or 6 = (100) or (110)=(110)=6
代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <iostream>
#include <algorithm>
#include <string>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <bitset>
using namespace std;
const int maxn=100000+100;
int N,M,A[maxn][33],sum[maxn][33];
int main(int argc, char* argv[])
{
int zz=0;
scanf("%d",&zz);
for (int test=1; test<=zz; test++) //while(zz-)
{
scanf("%d%d",&N,&M);
for (int i=1; i<=N; i++) //N个数据的输入采集
{
int x;
scanf("%d",&x);
for (int j=0; j<31; j++)
{
A[i][j]=(x>>j)&1; //拆分每个数据的每个位数,二进制,按低到高序排列
//printf ("%d ",A[i][j]);
}
//printf ("#1\n");
}
for (int j=0; j<31; j++)
{
sum[0][j]=0; //sum二维数组初始化
//printf ("%d ",sum[0][j]);
}
// printf ("&\n");
for (int i=1; i<=N; i++)
{
for (int j=0; j<31; j++)
{
sum[i][j]=sum[i-1][j]+A[i][j]; //将拆散的数据依次按位相加
// printf ("%d ",sum[i][j]);
}
// printf ("#2\n");
}
while(M--) //M次询问
{
int x,y;
scanf("%d%d",&x,&y); //询问范围数据范围
int ans=0;
for (int j=0; j<31; j++)
{
if (sum[y][j]-sum[x-1][j]>0) //从x-1到y位数据中,该位有1出现
{
// printf ("%d %d\n",sum[y][j],sum[x-1][j]);
ans|=(1<<j); //(1<<j)得到该位数据的十进制表示的值
// printf ("(1<<j)=%d ans=%d\n",1<<j,ans);
}
}
printf("%d\n",ans);
}
}
return 0;
}
总结
面对这道题,自己一上来就傻逼的建立数组存储数据,然后循环[x,y]里面的 ‘|’ 运算,但是自己就没有考虑过时限问题。数据范围是10^5,每个数据又是32位,运行达到了2800ms,严重超时。
C :最萌身高差
题目:
fq进入了ccnu神奇的acm实验室,出去比赛的时候拍合照。fq观察照片发现大家都从左到右站成一排,更神奇的是:他发现实验室队员里出现了最萌身高差。于是,fq翻出了更多的黑历史,想找出每张照片的最萌身高差。
每张照片,有n个人,所有人从左到右排成一排,身高差定义为相邻两个人的身高差的绝对值,最萌身高差就是指所有身高差最大的那个。
输入格式:
第一行一个整数T,表示T组数据。
每组数据首先有一行一个整数,表示人数n(1<=n<=10^4)。
接下来n行,每行一个字符串和一个整数,表示该位置的人的名字和身高。字符串长度不超过20,整数不超过300
输出格式:
对于每组数据,输出两行。
第一行输出一个整数,表示最萌身高差是多少。
第二行输出两个字符串(中间用一个空格隔开),表示最萌身高差的两个人是谁(按从左到右输出,如果有多个,输出最左边的两个人)
输入样例:
1
6
wh 175
fq 165
wq 170
gbx 165
xb 190
ooc 175
输出样例:
25
gbx xb
代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <iostream>
#include <algorithm>
#include <string>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <bitset>
using namespace std;
const int maxn=10000+100;
int N,A[maxn];
char name[maxn][25];
int main(int argc, char* argv[])
{
int zz=0;
scanf("%d",&zz);
for (int test=1; test<=zz; test++)
{
scanf("%d",&N);
for (int i=1; i<=N; i++) scanf("%s%d",name[i],&A[i]);
int ans=-1,k;
for (int i=1; i<N; i++)
{
int ret=abs(A[i]-A[i+1]);
if (ret>ans) ans=ret,k=i;
}
printf("%d\n",ans);
printf("%s %s\n",name[k],name[k+1]);
}
return 0;
}
总结
这是一道简单题,我都能做出来,考的就是字符串的输入输出而已,再就是简单的按序查找。
D:gcd和lcm
题目:
gbn在教小朋友数论,他在黑板上写了一个题:给出两个正整数x和y,其中gcd(a,b)=x,lcm(a,b)=y,问有多少对满足条件的正整数解(a,b)?
gcd是两个数的最大公约数,lcm是两个数的最小公倍数。
输入格式:
第一行一个整数T,表示数据组数。(T<=20)
接下来T行,每行两个正整数,表示x和y。(1<=x , y<=10^6)
输出格式:
对于每一个数据,输出一行一个整数g,表示有g对(a,b)满足条件。
输入样例:
3
1 12
3 12
2 24
输出样例:
4
2
4
代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <iostream>
#include <algorithm>
#include <string>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <bitset>
using namespace std;
#define bll long long
#define dou double
#define For(i,a,b) for (int i=(a),_##i=(b); i<=_##i; i++)
#define Rof(i,a,b) for (int i=(a),_##i=(b); i>=_##i; i--)
#define rep(i,a,b) for (int i=(a),_##i=(b); i<=_##i; i++)
#define rek(i,a,b) for (int i=(a),_##i=(b); i>=_##i; i--)
#define Mem(a,b) memset(a,b,sizeof(a))
#define Cpy(a,b) memcpy(a,b,sizeof(b))
int gcd(int a,int b)
{
if (b==0) return a;
return gcd(b,a%b);
}
int main(int argc, char* argv[])
{
int zz=0;
scanf("%d",&zz);
for (int test=1; test<=zz; test++)
{
int x,y;
scanf("%d%d",&x,&y);
if (y%x!=0) //公因数和公倍数互质
{
printf("0\n");
continue;
}
int r=y/x; //a,b两数都除去公因数,较小的数的范围小于sqrt(r),或者说小于max(k1,k2)*x;
int ans=0;
for (int i=1; i*i<=r; i++)
if (r%i==0 && gcd(i,r/i)==1) //i是r的因数,同时i与r/i互质
{
ans++;
if (i!=r/i) //a!=b,数据位置可以颠倒
ans++;
}
printf("%d\n",ans);
}
return 0;
}
总结:
x=gcd(a,b);
y=lcm(a,b)=a*b/gcd(a,b);
x * y=a * b;
a=k1 * x,b=k2 * x(k1,k2互质,);
y=k1 * k2 * x;
自己的傻逼方法当然超时限了,数据范围是10^6,自己也一直没有找到循环的范围是i*i<=r;
E:战火纷飞
题目:
一天WH睡醒之后发现自己竟然穿越到了一个战火纷飞的朝代,而且他还是一个国君,尽管如此不可思议,但是WH内心毫无波动,甚至还想睡觉。这时候一个御用太监递上了一份册子,WH定睛一看,这是现在各个国家的战斗力表,WH知道,只要战斗力比自己低或者相等的国家就能打败他们,而且如果现在他去攻打一个国家战斗力只有自己国家的一半或者一半以下的国家,那么他将毫不费力地拿下这个国家,并且被战败的这个国家的战斗力将会全部加到自己国家上,但是如果他去攻打一个国家战斗力超过自己国家战斗力一半的国家,打败这个国家之后,自己国家的战斗力会增加上战败国战斗力的一半,现在由于WH刚睡醒所以不想看这个战斗力表,所以他想把这个战斗力表给你,让你算算他最终能不能打败所有国家,如果能输出他的国家最终能达到的最高的战斗力,如果不能,输出-1。(文中所有的除法计算若不能整除,则向下取整)
国家的数目n的范围为[1, 10000], 该战斗力表上所有国家的战斗力范围都在[1,INT_MAX]内。
注意:战斗力相等的国家也可以打赢。
Input:
多组数据。
每组数据的第一行为一个数字n,表示有n个国家。接下来的一行有n个数字,代表n个国家的战斗力,其中第一个数为WH所在国家的战斗力。
Output:
对于每组数据,输出一个数:若WH能够打败所有国家则输出他的国家能达到的最大的国家战斗力,如果不能输出-1。
Sample Input
5
9 2 10 4 13
5
5 9 8 14 2
Sample Output
26
-1
Hint:
第一组样例解释:先把战斗力为4的国家打败,自己国家的战斗力上升为13,再把战斗力为2的国家打败,自己国家的战斗力上升为15,再把战斗力为10的国家打败,自己国家的战斗力上升为20,再把战斗力为13的国家打败,自己国家的战斗力上升为26
第二组样例解释:先把战斗力为2的国家打败,自己国家的战斗力上升为7,无法继续打败其他国家。
总结:
个人的思路是,先将国家战力值排个序,依次打下去,知道打完或者打不赢。当然这是多么的单纯啊。这个世界慢慢的恶意告诉我,当碰到10 6 8
这个情况的时候,先打8更好一些,然后就以为应该每次打完战力值一半及一下之后,就选择获益最高的(打8获得4,打6获得3),但可恶的世界又告诉我,碰到20 12 13
时 先打12更好一些,这里要是有表情,真想掩面痛哭啊、、、然后蠢蠢的我就不知道能干嘛呢、、
时间: 2024-10-16 18:05:14