Summary
昨天的 题目预测 准确率 1/7=14.29%,也算是意料之中吧。
毕竟是个考试嘛,而且似乎可能差不多已经暴露了预测吧。
什么?你没看到昨天的题目预测?再仔细观察一下那个 peach 吧,
难道你就没有怀疑过我为啥要把它扔进 CTF 专栏吗?
我会真的发一个 peach 吗?Of course not!
好吧,如果你实在没有发现,请看本文末尾的彩蛋 ~
至于这个官方题解里的六花嘛。。emm…
应该不是我,估计不是我,肯定跟我没关系,嗯,就这样吧 2333…
Information
No. | Title | AC/Submit |
---|---|---|
A | 机器人 | 60/146 |
B | 纸牌游戏 | 68/165 |
C | 咸鱼连突刺 | 37/289 |
D | 库特的合并果子 | 58/313 |
E | 库特的素数队列(1) | 32/125 |
F | 库特的素数队列(2) | 17/76 |
G | 库特的绳子 | 7/57 |
Problem A: 机器人 (1295) [60/146]
Tips
这个题方法很多,我是把原数和倒过来的数存在结构体里排序
按倒过来之后的数排序,再输出原数即可。
这个排序正好练练优先队列的重载,直接写 cmp 也可以。
像题解那样读入字符串进行处理也是一个挺好的方法。
Code
#include <bits/stdc++.h>
using namespace std;
struct number
{
int ori;
int fx;
}num;
bool operator < (const number &p1,const number &p2)
{
return p1.fx>p2.fx;
}
int main()
{
priority_queue<number>q;
int n,x,cnt,tmp;
while(cin>>n)
{
while(n--)
{
cin>>x;
num.ori=x;
tmp=0;
while(x>0)
{
tmp*=10;
tmp+=x%10;
x/=10;
}
num.fx=tmp;
q.push(num);
}
while(q.size()>1)
{
cout<<q.top().ori<<" ";
q.pop();
}
cout<<q.top().ori<<endl;
q.pop();
}
return 0;
}
Problem B: 纸牌游戏 (1311) [68/165]
Tips
这个算是个简单的签到题吧,注意行尾别多打逗号即可。
Code
#include <bits/stdc++.h>
using namespace std;
int main()
{
queue<int>q;
int t,n;
cin>>t;
while(t--)
{
cin>>n;
while(!q.empty())q.pop();
for(int i=1;i<=n;i++)
{
q.push(i);
}
while(q.size()>2)
{
cout<<q.front()<<",";
q.pop();
q.push(q.front());
q.pop();
}
if(q.size()>1)
{
cout<<q.front()<<endl;
q.pop();
}
cout<<q.front()<<endl;
}
return 0;
}
Problem C: 咸鱼连突刺 (2114) [37/289]
Tips
这个主要考的是读题,嗯,就是读题,题看懂了就没问题了
取 L 和 R 之间最大的素数与最小的素数之和的伤害值(包括L和R)
如果 L R 之间只有一个素数,那就加它的二倍
如果 L R 之间没有素数就不加(加上 0)
Code
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e6+1;
char prime[MAXN];
int primeList[MAXN],num=0;
void getPrime()
{
memset(prime,1,sizeof(prime));
prime[0]=prime[1]=0;
for(int i=2;i<MAXN;i++)
{
if(prime[i])primeList[num++]=i;
for (int j=0;j<num&&i*primeList[j]<MAXN;j++)
{
prime[i*primeList[j]]=0;
if(i%primeList[j]==0)break;
}
}
}
int main()
{
getPrime();
int t,l,r,pos1,pos2;
long long sum=0;
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&l,&r);
pos1=lower_bound(primeList,primeList+num,l)-primeList;
pos2=upper_bound(primeList,primeList+num,r)-primeList-1;
if(pos1<num&&primeList[pos1]>r||pos2>=0&&primeList[pos2]<l);
else sum+=primeList[pos1]+primeList[pos2];
}
printf("%lld\n",sum);
return 0;
}
Problem D: 库特的合并果子 (2110) [58/313]
Tips
这个就直接在昨天那个三题通杀代码的基础上改就可以了。
主要改动就是把输出总和改成输出过程了,
还要注意处理一下每组数据行尾的空格,不要多打印空格。
Code
#include <bits/stdc++.h>
using namespace std;
int main()
{
priority_queue<long long,vector<long long>,greater<long long> >q;
long long tmp,n;
while(cin>>n)
{
while(!q.empty())q.pop();
while(n--)
{
cin>>tmp;
q.push(tmp);
}
while(q.size()!=1)
{
tmp=q.top();
q.pop();
tmp+=q.top();
q.pop();
q.push(tmp);
if(q.size()!=1)cout<<tmp<<" ";
}
cout<<tmp<<endl;
}
return 0;
}
Problem E: 库特的素数队列(1) (2111) [32/125]
Tips
T ≤ 3 这个范围好啊,直接用队列模拟就可以了。
Code
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e7+1;
char prime[MAXN];
int primeList[MAXN],num=0;
void getPrime()
{
memset(prime,1,sizeof(prime));
prime[0]=prime[1]=0;
for(int i=2;i<MAXN;i++)
{
if(prime[i])primeList[num++]=i;
for (int j=0;j<num&&i*primeList[j]<MAXN;j++)
{
prime[i*primeList[j]]=0;
if(i%primeList[j]==0)break;
}
}
}
int main()
{
queue<int>q;
getPrime();
int t,n,cnt,qs;
cin>>t;
while(t--)
{
cin>>n;
for(int i=1;i<=n;i++)q.push(i);
while(q.size()!=1)
{
qs=q.size();
for(int i=1;i<=qs;i++)
{
if(q.size()==1)break;
if(prime[i])q.push(q.front());
q.pop();
}
}
cout<<q.front()<<endl;
q.pop();
}
return 0;
}
Problem F: 库特的素数队列(2) (2112) [17/76]
Tips
T ≤ 30000 这个范围就有点吓人了,本地跑都没停下来。
那就找找规律吧,正好用上面 E 题打个表试试。
不用都打出来,打一会就看出规律了,很容易看出来。
总共也没几组,暴力 if 都没啥问题。
我放在程序里现打的,也确实没多少。
Code
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e7+1;
char prime[MAXN];
int primeList[MAXN],num=0;
void getPrime()
{
memset(prime,1,sizeof(prime));
prime[0]=prime[1]=0;
for(int i=2;i<MAXN;i++)
{
if(prime[i])primeList[num++]=i;
for (int j=0;j<num&&i*primeList[j]<MAXN;j++)
{
prime[i*primeList[j]]=0;
if(i%primeList[j]==0)break;
}
}
}
int anstab[MAXN],an=0;
void getAns()
{
for(int i=1;i<num;)
{
i=anstab[an++]=primeList[i-1];
}
}
int main()
{
ios::sync_with_stdio(0);
getPrime();
getAns();
int t,n,cnt,qs,pos;
cin>>t;
while(t--)
{
cin>>n;
if(n==1)
{
cout<<1<<endl;
continue;
}
pos=upper_bound(anstab,anstab+an,n)-anstab-1;
cout<<anstab[pos]<<endl;
}
return 0;
}
Problem G: 库特的绳子 (1949) [|7/57]
Tips
这就是那个唯一预测出来的题目了,早知道就提前研究研究了,
要不然也不能 WA +TLE 错成这个样子 /(ㄒoㄒ)\~~
这题还是不太好想的,起初打算列出所有间隔,
然后再排序比较,后来一想,这800%TLE啊。
由于 两根靠近的钉子之间的间隔一定是最小的,所以先把靠近的钉子之间的间隔扔进优先队列,这样优先队列的队首一定是最短的间隔。
间隔采用结构体存储,分别存储左边的钉子,右边的钉子和间隔长度。
同时对绳子进行排序,从最短的绳子开始 依次往钉子上挂。
每取出一根最短的绳子,消耗一个最短的间隔 (pop一次)
同时还要 向优先队列中插入一个向右延伸的间隔 即右端点 +1
(注意插入时要检测边界,不能越界。)
这样始终 保持优先队列中的队首是未被使用的最小间隔。
当队列为空或者有绳子挂不上了,即为失败,输出 no
否则顺利挂完绳子,圆满结束即为成功,输出 yes
考试的时候人都傻了,时间越少越着急,把 m 打成 n 了还交了 3 遍,
今天真的是太菜了 /(ㄒoㄒ)\~~
Code
#include <bits/stdc++.h>
using namespace std;
struct pinlen
{
int l,r,len;
}tmp;
bool operator < (const pinlen &p1,const pinlen &p2)
{
return p1.len>p2.len;
}
priority_queue <pinlen>q;
const int MAXN=5e5+1;
int ppos[MAXN];
int slen[MAXN];
int main()
{
int n,m,pts,i;
while(~scanf("%d %d",&n,&m))
{
pts=0;
while(!q.empty())q.pop();
for(i=0;i<n;i++)scanf("%d",&ppos[i]);
sort(ppos,ppos+n);
for(i=0;i<n-1;i++)
{
tmp.l=i;
tmp.r=i+1;
tmp.len=ppos[i+1]-ppos[i];
q.push(tmp);
}
for(i=0;i<m;i++)scanf("%d",&slen[i]);
sort(slen,slen+m);
bool flag=false;
for(i=0;i<m;i++)
{
if(q.empty())break;
tmp=q.top();
q.pop();
if(slen[i]<tmp.len)break;
if(tmp.r+1<n)
{
tmp.r++;
tmp.len=ppos[tmp.r]-ppos[tmp.l];
q.push(tmp);
}
}
if(i==m)printf("yes\n");
else printf("no\n");
}
return 0;
}
彩蛋一枚
昨天的题目预测,你看明白了吗?
Step 1. 打开开发者选项,找到未被压缩的图片原图。
Step 2. 打开链接,右键保存图片,改后缀为 zip 打开。
剩下的我不说你也知道题目在哪里了 ヾ(≧▽≦*)o
其实我在就预料到这次预测不会准,所以随便 “皮” 了一下 ~