问题 A: 逃跑路线
时间限制: 1 Sec 内存限制: 128 MB
题目描述
n个人在w*h的监狱里面想要逃跑,已知他们的同伙在坐标(bi,h)接应他们,他们现在被关在(ai,1)现在他们必须要到同伙那里才有逃出去的机会,这n个人又很蠢只会从(x,y)->(x+1,y),(x,y+1)并且这他们走过的路径不能相交如果相交第一个经过后就会有第二个人经过时候就会有一名狱警在那等他,第二个人就会被抓,假设他们不会同时踩到某个格子,那么他们的逃跑路线有多少不同的方案数。如果两个方案不同那么存在一个人踩的格子至少有一个是另外一个方案的没踩过
输入
第一行一个t(t<=20)表示测试样例
第二行两个3个正整数n,w,h(n<=100,w,h<=1e9)
接下来n行每行两个整数
ai,bi(ai,bi<=w)
输出
输出一个整数表示答案最终结果取膜109*1000003
样例输入
1
2 4 2
1 2
3 4
样例输出
4
题解:
水平不够这题我不会, 有兴趣搜索hdu5852一样类型的题
董哥tql上来就把这题给补了: 董哥博客
问题 B: 嘉琦的暑期集训之迟到篇
时间限制: 1 Sec 内存限制: 128 MB
题目描述
嘉琦暑期上班天天迟到,然后-LS准备去蹲点抓嘉琦,然后让他上去讲题(连牌都不用发了),傅老师会在某个时间段选一个时间点从南区走到理工楼抓嘉琦,嘉琦会在某个时间点(肯定迟到)并且有行走的时间去理工楼上班。那么现在求-LS抓到嘉琦概率,嘉琦没被抓到就是在-LS之前到达理工楼
输入
第一行一个T表示样例格式T<=1000
第二行五个a:b:c代表时间以空格分开,分别代表时间秒 a<23,b<60,c<60
第一个时间代表-LS时间段的开头
第二个时间代表-LS时间段的结尾
第三个时间代表-LS走到理工楼需要的时间
第四个时间代表嘉琦从宿舍出发的时间
第五个时间代表嘉琦走到理工楼需要的时间
保证任何情况这两个人走到理工楼的时间都在24:00:00前
输出
输出小数点后两位
样例输入
2
00:00:00 00:00:00 00:00:00 00:00:00 00:00:00
00:00:00 00:00:59 00:00:20 00:00:29 00:00:20
样例输出
1.00
0.50
提示
第二样例-ls只要在0~29时间段出发都可以,那么就是0~59的一半时间所以是0.50
题解:
先预处理把题目给的时间都转成秒以便计算,再算出jq到达理工楼时间再扣去fls行走所需时间,得到fls想要抓到jq的最迟出发时间,分三种情况考虑最迟出发时间在fls出发时间端的左边, 中间,以及右边
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int Time[10];
int main() {
int T;
scanf("%d", &T);
while (T--) {
int x, y, z;
for (int i = 1; i <= 5; i++) {
scanf("%d:%d:%d", &x, &y, &z);
Time[i] = x*3600 + y*60 + z;
}
int fls = Time[4] + Time[5] - Time[3];//fls最晚可抓到jq的出发时间;
if (fls >= Time[2]) printf("1.00\n");
else if (fls < Time[1]) printf("0.00\n");
else printf("%.2f\n", 1.0 * (fls-Time[1]+1) / (Time[2]-Time[1]+1));
}
return 0;
}
问题 C: 二进制?十进制?四进制!
时间限制: 1 Sec 内存限制: 128 MB
题目描述
恭喜你,这个问题不是你以前用的十进制也不是你现在耍的二进制。
如果给你一个四进制的正整数,你能找到一个形如2^k(就是2的k次方,k是非负整数)的数使得它是这个四进制数的整数因子吗?
如果有多个k满足条件,我只需要知道最大值。
输入
输入包含多组样例。
第一行输入一个数n代表四进制数的位数.(1<=n<=1e6)
第二行输入长度为n个字符串描述这个四进制数。
保证所有样例∑n不会超过2e6
输出
每个样例输出一行整数代表k的最大值。
样例输入
3
311
2
10
样例输出
0
2
提示
恭喜你,签到成功!但没有奖励[○・`Д´・ ○]
题解:
学过位移运算可以知道要把一个数乘以2只需在在二进制下左移一位, 相当于C语言里的(X<<1),左移1位相当于给这个数最右边补一个0,左移两位(相当于这个数乘以4)就是补两个0, 同理要把数除以2,4,8,16相当于右移1,2,3,4位,也就是删除右边的1,2,3,4个0,题目给的除数是2^k方也就等于求这个数最多能删去右边几个0, 所以只要把这个四进制数从右向左转成2进制,再判断从最右边开始有几个连续的0
而每一位4进制数可以转成两位2进制数
代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int mx = 2e6+5;
char str[mx];
int main() {
int n;
while (scanf("%d", &n) != EOF) {
scanf("%s", str);
int ans = 0;
for (int i = n-1; i >= 0; i--) {
if ((str[i]-'0') % 2 % 2 == 0) ans++;
else break;
if ((str[i]-'0') / 2 % 2 == 0) ans++;
else break;
}
printf("%d\n", ans);
}
return 0;
}
问题 D: jq乘法运算
时间限制: 1 Sec 内存限制: 128 MB
题目描述
jq定义一个数的表示方法为x(n) = (a1,a2,a3,a4.,..an),ai(1<=i<=n)是一个三位数(可能包含前导0,比如001)
x(n)是一个3*n位的数,x = a1a2a3..an,例如123456(2) = (123,456)。
jq自定义一个位数相同的两个数的乘法运算为:
x(n)*y(n) = (a1*b1%1000,a2*b2%1000,a3*b3%1000,....,an*bn%1000) = z(n)
例如123456(2)*456123(2) = (123*456%1000,456*123%1000) = (088,088) = 088088;
现在jq想用这个规则考一考fuls,jq给了fuls一个3*n位数的数z,要求fuls求出两个3*n位数的数x,y使得它们用上面定义的乘法乘积等于z。
聪明的fuls一下子就解出了x和y,于是他在当晚就把答案写在了纸上,等他醒来时发现x和y的某些ai,bj(1<=i,j<=n)的数已模糊不清(估计是jq干的)(如果某个ai或者bj模糊不清,那么代表其三位数都模糊不清)。
此时jq正好赶来问结果,但fuls一时想不起来那些模糊的数了,此时他想找你帮他回忆那些数,你可以帮帮fuls吗?
与此同时jq为了继续刁难fuls他要求可行的x尽量小,也就是你必须解出一个最小的x使得有对应的y与它相乘等于z。(若你得到的不是最小的x,jq会认定他是错的)
同样在得到最小的x时,y也必须是答案中最小的一个,否则也认为是错误的。 (注意x,y,z可能有前导0)
输入
第一行包含一个t表示样例个数。
接下来t行每行一个整数n表示数的位数为3*n(1<=n<=1e6)。
每行n都接着三行3*n位数的数,第一行表示z,第二行表示x,第三行表示y(x和y中*号部分表示模糊不清的数)。
保证所有样例∑n<=1e6
输出
每个样例输出两行3*n位数,第一行表示将模糊地方填补完的x,第二行表示将模糊地方填补完的y(若有前导0则一起输出)。
样例输入
3
2
088088
123***
***456
2
784784
456***
789***
2
784784
456***
***789
样例输出
123123
456456
456001
789784
456456
039789
提示
在第二个样例中x取456456时y可以取最小得039789,但必须先满足x最小,所以先x取得有解最小值456001后y取得此条件下的最小值789784.
在第三个样例中x取有解最小值456456时,此时y取此条件下最小值039789(789789>039789)。
题解:
题目问题转化为给你a, c问a * b % 1000 = c这个方程的所有解b中最小的一个, 由于数字只有3位,我们可以暴力预处理出这个方程的所有解,用ans[i][j]记录当a = i, c = j时的最小解b,当x和y都是*时分两种情况讨论,如果z=0,则取x=0, y=0,否则取x=1,y=z。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int mx = 3e6+5;
const int inf = 99999999;
char x[mx], y[mx], z[mx];
int ans[1005][1005];
int main() {
for (int i = 0; i < 1000; i++)//ans数组要先初始化成正无穷
for (int j = 0; j < 1000; j++)
ans[i][j] = inf;
for (int i = 0; i < 1000; i++) {//预处理出所有解
for (int j = 0; j < 1000; j++) {
int tmp = i*j % 1000;
ans[i][tmp] = min(ans[i][tmp], j);
}
}
int T;
scanf("%d", &T);
while (T--) {
int n;
scanf("%d", &n);
scanf("%s%s%s", z, x, y);
for (int i = 0; i < 3*n; i += 3) {
int numx, numy, numz, ansx, ansy;
if (x[i] == '*') numx = -1;
else numx = (x[i]-'0')*100 + (x[i+1]-'0')*10 + (x[i+2]-'0');
if (y[i] == '*') numy = -1;
else numy = (y[i]-'0')*100 + (y[i+1]-'0')*10 + (y[i+2]-'0');
numz = (z[i]-'0')*100 + (z[i+1]-'0')*10 + (z[i+2]-'0');
if (numx == -1 && numy == -1) {
if (numz == 0) {
ansx = 0; ansy = 0;
}
else {
ansx = 1; ansy = numz;
}
}
else if (numx == -1) {
ansx = ans[numy][numz];
ansy = numy;
}
else {
ansy = ans[numx][numz];
ansx = numx;
}
if (numx == -1) {
x[i] = ansx / 100 + '0';
x[i+1] = ansx / 10 % 10 + '0';
x[i+2] = ansx % 10 + '0';
}
if (numy == -1) {
y[i] = ansy / 100 + '0';
y[i+1] = ansy / 10 % 10 + '0';
y[i+2] = ansy % 10 + '0';
}
}
printf("%s\n%s\n", x, y);
}
return 0;
}
问题 E: 这是一题emmmm你自己理解吧
时间限制: 2 Sec 内存限制: 128 MB
题目描述
给你一段代码你可以尝试贴上去看能不能过,现在要你写个程序答案和下列代码一样
#include<stdio.h>
int main(){
int t;
scanf("%d",&t);
while(t--){
long long n;
scanf("%lld",&n);
long long ans = 0;
for(long long i = 1; i <= n; i++)
ans ^= i;
printf("%lld\n",ans);
}
return 0;
}
输入
一个数字t表示样例个数(t<=1e4)
输入两个正整数n(n<=1e18)
输出
输出一个数表示答案
样例输入
1
6
样例输出
7
题解:
这种让你直接贴代码的肯定都是骗鬼的。。。遇事不决先打表看一下规律
n = 1 ans = 1
n = 2 ans = 3
n = 3 ans = 0
n = 4 ans = 4
n = 5 ans = 1
n = 6 ans = 7
n = 7 ans = 0
n = 8 ans = 8
n = 9 ans = 1
n = 10 ans = 11
n = 11 ans = 0
n = 12 ans = 12
n = 13 ans = 1
n = 14 ans = 15
n = 15 ans = 0
n = 16 ans = 16
n = 17 ans = 1
n = 18 ans = 19
n = 19 ans = 0
n = 20 ans = 20
发现每隔4位就会出现一个0,那么我们只要从最接近n的那个0开始异或到n,这样最多只要计算4次
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int main() {
int T;
scanf("%d", &T);
while (T--) {
long long n, ans = 0;
scanf("%lld", &n);
for (long long i = n/4*4; i <= n; i++)
ans ^= i;
printf("%lld\n", ans);
}
return 0;
}
问题 F: jq解救fuls
时间限制: 1 Sec 内存限制: 128 MB
题目描述
一天fuls被邪恶的"咕咕咕"抓走了,jq为了救fuls可谓是赴汤蹈火,费了九牛二虎之力才找到了"咕咕咕"关押fuls的地方。
fuls被关在一个机关中,想要解救fuls必须解答出机关的问题,在机关上会显示两个整数N和M,jq必须在机关上输入N个只包含'A'和'C'的字符形成串str,
在这个串中存在f(i,j),i<j,表示str[i]=='C'和str[j]=='A'的一个反AC对,此字符串必须包含刚好M个反AC对,如果有多个长度为N的串满足条件,那么字典序最大的那个才是正确的。
字典序大小:
若字符串a>字符串b即存在位置i使得0<=j<i,a[j]==b[j],a[i]>b[i]。
输入
第一行输入一个t表示样例个数。(1<=t<=100)
接下来t行每行包含两个整数N和M(1<=N<=60,0<=M<=N*(N-1)/2)
输出
每个样例输出一行字符串表示jq的答案,若某次询问无解则输出"jq lost fuls!"(输出无双引号)。
样例输入
2
5 4
3 3
样例输出
CCCCA
jq lost fuls!
提示
第一个样例中有f(1,4),f(2,4),f(2,4),f(3,4)一共四个,虽然CCAAC也满足条件但字典序不是最大所以输出最大CCCCA
题解:
贪心,既然要求字典序最大,首先肯定C越多越好,先暴力算出最多可以放多少个C,(当A和C个数却定时,反AC对最多为A的个数乘以C的个数,也就是C全放左边,A全放右边),接着贪心的考虑尽量把C放左边,例如n = 7, m = 11, 确定出C放4个A放3个,判断最多可以放多少个C在3个A的左边(11 / 3 = 3个), 此时已构造出9对反AC对,接着考虑可以放多少个C在2个A的左边(剩余2个反AC对, 2 / 2 = 1个),接着考虑多少个C放在1个A的左边(0 / 1 = 0), 最后如果还剩下C则全放最右边,最后构造出的字符串为CCCACAA
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int cnt[65];
int main() {
int T;
scanf("%d", &T);
while (T--) {
memset(cnt, 0, sizeof(cnt));
int n, m, A, C;
scanf("%d%d", &n, &m);
if (n/2 * (n-n/2) < m) {//n/2 * (n-n/2)为最多可以构造出的反AC对
printf("jq lost fuls!\n");
continue;
}
for (int i = n; i >= 0; i--) {//计算最多可放多少个C
if (i*(n-i) >= m) {
C = i;
break;
}
}
A = n - C;
for (int i = A; i >= 1; i--) {
cnt[i] = m / i;
m -= m / i * i;
}
for (int i = A; i >= 1; i--) {
for (int j = 1; j <= cnt[i]; j++) {
putchar('C');
C--;
}
putchar('A');
}
while (C--) putchar('C');//剩余的C全放右边
putchar('\n');
}
return 0 ;
}
问题 G: jq请客辣
时间限制: 1 Sec 内存限制: 128 MB
题目描述
众所周知,jq和他的两个小基友老罗和辉哥在沈阳拿了块牌牌,为了庆祝,他邀请集训队的n个队员吃饭(包括jq,老罗和辉哥),但是jq又要 刷题学习,所以他请了fuls来帮忙张罗。集训队的队员都知道fuls是一个有强迫症的人,只要是他张罗的晚宴,桌子上的每一个盘子都必须不重叠,但是可以接触,并且每个盘子都必须接触桌子的边缘,现在已知吃饭的人数,桌子半径和盘子半径分别为n,R,r,你能帮帮fuls计算下这张桌子能坐下n个人么。每个人用且只能用一个盘子。
输入
测试输入包含若干个测试用例,每个测试用例占一行,一行包含三个整数n,R,r ( 0 <= n, R, r <= 1000 ) 含义如上所述。
输出
每个测试用例输出包含一行
如果可以坐下n个人,输出YES
反之则输出NO
样例输入
1 1 1
2 2 1
2 1 2
5 10
样例输出
YES
YES
NO
NO
题解:
先特判几种特殊情况,r > R以及r > 0.5 R的情况
接着高中几何知识计算每个盘子占去的角度,最后2PI除以这个角度就是最多能放的盘子数
(这题貌似不用考虑R,r = 0的情况)
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int main() {
int n, R, r;
double pi = 3.141593;//精度问题这里PI设稍大了一点
while (scanf("%d%d%d", &n, &R, &r) != EOF) {
if (r > R) {
if (n == 0) puts("YES");
else puts("NO");
continue;
}
if (2*r > R) {
if (n <= 1) puts("YES");
else puts("NO");
continue;
}
double Sin = 1.0 * r / (R-r);
int num = pi / asin(Sin);
if (num >= n) puts("YES");
else puts("NO");
}
return 0;
}
问题 H: 这应该是最良心的一题了
时间限制: 1 Sec 内存限制: 128 MB
题目描述
给你两个数n,m;再给你n个数ai,m个数bi
求n个数的乘积除以m个数的乘积是否为质数
即求(a1*a2*...*an)/(b1*b2*...*bm)的结果是否为质数
输入
测试输入包含若干个测试用例
每个测试用例的第一行包含两个整数n,m(1 <= n, m <= 10000)
第二行包括n个整数ai (1 <= i <= n, 1 <= ai <= 30000)
第三行包括m个整数bi(1 <= i <= m, 1 <= bi <= 30000)
ai和bi大部分数据范围为[1, 10000]
输出
每个测试用例输出一行,若结果为质数输出YES
反之则输出NO
样例输入
1 1
1
1
1 1
5
2
样例输出
NO
NO
提示
小数和分数都不为质数
题目中所属的除法( / )为普通除法
题解:
这题正解是唯一分解定理,出题人没卡精度所以double能过
定理详细内容参考百科,大致就是任何大于1的自然数都可以分解成质数次方的乘积,比如60分解成,63分解成
所以这题我们把分子所有乘数都分解并把次方都加起来,比如60*63 = ,分母也同样处理,最后把分子的次方减去分母的次方,
判断剩下的这个数是否为质数,判断方法为剩下的结果中只有一个次方为1的数,例如 显然结果为质数,而
显然不是质数
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int mx = 30005;
int cnt[mx], prime[mx], vis[mx], tot = 0;
void getPrime() {
memset(vis, 0, sizeof(vis));
for (int i = 2; i < mx; i++)
{
if (!vis[i])
prime[tot++] = i;
for (int j = i + i; j < mx; j += i)
vis[j] = 1;
}
}
int main() {
getPrime();//打出素数表
int n, m, num;
while (scanf("%d%d", &n, &m) != EOF) {
memset(cnt, 0, sizeof(cnt));
for (int i = 1; i <= n; i++) {
scanf("%d", &num);
for (int j = 0; j < tot && prime[j]*prime[j] <= num; j++) {//分解
if (num % prime[j] == 0) {
while (num % prime[j] == 0) {
num /= prime[j];
cnt[prime[j]]++;//统计质数prime[i]的次方数
}
}
}
if (num > 1) cnt[num]++;
}
for (int i = 1; i <= m; i++) {
scanf("%d", &num);
for (int j = 0; j < tot && prime[j]*prime[j] <= num; j++) {
if (num % prime[j] == 0) {
while (num % prime[j] == 0) {
num /= prime[j];
cnt[prime[j]]--;//分子是加分母是减
}
}
}
if (num > 1) cnt[num]--;
}
int a = 0, b = 0, c = 0;//a记录次方为1的个数,b记录次方大于1的个数,c记录次方小于0的个数
for (int i = 0; i < mx; i++) {
if (cnt[i] == 1) a++;
if (cnt[i] > 1) b++;
if (cnt[i] < 0) c++;
}
if (a == 1 && b == 0 && c == 0) puts("YES");
else puts("NO");
}
return 0;
}