Summary
今天的题一点也不友好(好吧,是我太菜了) /(ㄒoㄒ)\~~
昨天 题目预测 准确率 所有题目:6/10=60% 预测题目:6/7=85.71%
感觉预测被发现针对了(包括但不限于加强数据,增加新题…),瑟瑟发抖 ing
早上临时加题了,昨天数据又被疯狂强化了一波,感觉到了不是很友好的气息 ~
一大早上看到 root 正在疯狂提交就知道估计多半是废了
▲ 疯狂提交的 root 和瑟瑟发抖的我 → (@_@)
以下关于 素数筛 筛素数 这类的代码就不另外说明了
详情请参考以前的一篇文章:C/C++ 素数筛 ACM算法
Information
No. | Title | AC/Submit |
---|---|---|
A | 纯素数 | 15/122 |
B | 半素数 | 11/50 |
C | 函数版素数判定 | 43/241 |
D | 最大素因子 | 15/33 |
E | 素数与数论 | 9/59 |
F | 差点是素数 | 0/3 |
G | 高木同学的因子 | 27/38 |
H | 知否知否,应是绿肥红瘦 | 48/102 |
I | 素数线性筛 | 21/65 |
J | 五十弦翻塞外声 | 4/20 |
Problem A: 纯素数 (586) [15/122]
Tips
这个 A 题主要就是怎么去掉高位,筛完以后判断素数难度不大
可以先获取位数再获取最高位数字然后相乘,写成函数同时返回两个值
Code
#include <bits/stdc++.h>
using namespace std;
#define MAXN 1000001
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;
}
}
}
pair<int,int> getws(int n)
{
int cnt=1;
while(n/10)
{
cnt++;
n/=10;
}
return make_pair(cnt,n);
}
int main()
{
getPrime();
int n,ok,tmp;
pair<int,int> ret;
while(~scanf("%d",&n))
{
ok=1;
while(n>0)
{
ret=getws(n);
if(prime[n])n-=pow(10,ret.first-1)*ret.second;
else
{
ok=0;
break;
}
}
if(ok)printf("YES\n");
else printf("NO\n");
}
return 0;
}
Problem B: 半素数 (587) [11/50]
Tips
思路:不断的用素数去拆这个数,能拆就拆,
最后看总共拆成了几个数,正好是2个输出 YES 否则输出 NO。
Code
#include <bits/stdc++.h>
using namespace std;
#define MAXN 10001
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 n,cnt;
while(~scanf("%d",&n))
{
cnt=0;
for(int i=0;i<num&&primeList[i]<=sqrt(n);i++)
{
if(n%primeList[i]==0)
{
cnt++;
n/=primeList[i];
i=-1;
}
}
if(n!=1)cnt++;
if(cnt==2)printf("YES\n");
else printf("NO\n");
}
return 0;
}
Problem C: 函数版素数判定 (825) [43/241]
Tips
可以算是素数筛里比较基础的模(song)板(fen)题了吧。
Code
#include <bits/stdc++.h>
using namespace std;
#define MAXN 10000001
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 n;
while(~scanf("%d",&n))
{
if(prime[n])printf("YES\n");
else printf("NO\n");
}
return 0;
}
Problem D: 最大素因子 (585) [15/33]
Tips
可以先找到比这个数大的素数,再依次向前查找素数表中的素数是否为它的因子
关于 upper_bound
用法详见 C/C++ ACM 二分查找算法
Code
#include <bits/stdc++.h>
using namespace std;
#define MAXN 1000001
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 n,pos,ans;
while(~scanf("%d",&n))
{
if(n==1)
{
cout<<0<<endl;
continue;
}
pos=upper_bound(primeList,primeList+num,n)-primeList-1;
for(int i=pos;i>=0;i--)
{
if(n%primeList[i]==0)
{
printf("%d\n",i+1);
break;
}
}
}
return 0;
}
Problem E: 素数与数论 (781) [9/59]
Tips
直接 lower_bound
确定是第几个素数,然后相减即可。
注意:不要忘了处理边界为素数的情况。
关于 lower_bound
的用法也在这里:C/C++ ACM 二分查找算法
Code
#include <bits/stdc++.h>
using namespace std;
#define MAXN 1000001
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 x,y,cnt,pos1,pos2;
while(~scanf("%d %d",&x,&y))
{
cnt=0;
pos1=lower_bound(primeList,primeList+num,x)-primeList;
pos2=lower_bound(primeList,primeList+num,y)-primeList;
if(prime[y])pos2++;
printf("%d\n",pos2-pos1);
}
return 0;
}
Problem F: 差点是素数 (1321) [0/3]
Tips
比赛时:
差点是素数,差点就做出来了 /(ㄒoㄒ)\~~
样例都过了,就是疯狂 TLE /(ㄒoㄒ)\~~ x2
补题更新:
看了题解发现题解竟然又打了个表,我原来的那个读进去再算就来不及了
素数筛的部分就不说了,第二张表打的是 [1,1e12] 里满足条件的所有数
我以为会很多没敢打表,结果竟然没多少可以打表来做,amazing ~
有了第二张表就可以利用 lower_bound
和 upper_bound
快速计算了。
Code
#include <bits/stdc++.h>
using namespace std;
#define MAXN 1000001
char prime[MAXN];
long long 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;
}
}
}
long long pre[MAXN],pnum=0;
void getAns()
{
for(long long i=0;i<num;i++)
for(long long j=primeList[i]*primeList[i];j<=1e12;j*=primeList[i])
pre[pnum++]=j;
sort(pre,pre+pnum);
}
long long countans(long long l,long long r)
{
long long pos1=lower_bound(pre,pre+pnum,l)-pre;
long long pos2=upper_bound(pre,pre+pnum,r)-pre;
return pos2-pos1;
}
int main()
{
getPrime();
getAns();
int t,hb=1;
long long l,r,l1,r1,res;
scanf("%d",&t);
while(t--)
{
res=0;
hb=1;
scanf("%lld %lld %lld %lld",&l,&r,&l1,&r1);
if(l1>=l&&r1>=r&&l1<=r)r=r1;
else if(l1<=l&&r1<=r&&r1>=l)l=l1;
else if(l<=l1&&r>=r1);
else if(l1<=l&&r1>=r)l=l1,r=r1;
else hb=0;
if(hb)res=countans(l,r);
else res=countans(l,r)+countans(l1,r1);
printf("%lld\n",res);
}
return 0;
}
这个区间合并的代码有点笨,引用一下大佬 jwMM 的方法
cin>>l1>>r1>>l2>>r2;
if(l2>r1||l1>r2)sum=get_num(l1,r1)+get_num(l2,r2);
else
{
l=min(l1,l2);
r=max(r1,r2);
sum=get_num(l,r);
}
Problem G: 高木同学的因子 (1669) [27/38]
Tips
这个题其实已经见过了,当时也针对耗时优化过
再原来的基础上简单的改动了一下代码,可以说方法一点都没变
详细思路见原文章:NEFU 大一寒假训练五(GCD&&快速幂)2020.01.04
这不是巧了吗?当时也是 Problem G,题号都没变!
Code
#include <bits/stdc++.h>
using namespace std;
int main()
{
long long yz[10000],yp=0,yznum;
long long x,y,k,ans=0;
scanf("%lld %lld",&x,&y);
k=__gcd(x,y);
if(k==1)
{
cout<<1;
return 0;
}
for(int i=2;i<=k;i++)
{
if(k%i==0)
{
yz[yp++]=i;
k/=i;
i=1;
if(k==1)break;
continue;
}
}
ans=1;
yznum=1;
for(int i=1;i<yp;i++)
{
if(yz[i]==yz[i-1])
{
yznum++;
}
else
{
ans*=yznum+1;
yznum=1;
}
}
ans*=yznum+1;
printf("%lld",ans);
return 0;
}
Problem H: 知否知否,应是绿肥红瘦 (1704) [48/102]
Tips
这个大概可能好像差不多不筛也行(数据非常特别十分水,1e14吓人用的)
(我不会告诉你我手滑不小心写了个传统判断法就过了)
我难以置信的又交了一次,还真是!
▲ 我猜以后一定会强化数据的,除非他们不知道,嘿嘿嘿 ╰( ̄ω ̄o)
Code
#include <bits/stdc++.h>
using namespace std;
int isss(long long n)
{
for(long long i=2;i<=sqrt(n);i++)
{
if(n%i==0)return 0;
}
return 1;
}
int main()
{
long long x,y,z;
int n;
scanf("%d",&n);
while(~scanf("%lld %lld %lld",&x,&y,&z))
{
if(isss(x+y-z))printf("yes\n");
else printf("no\n");
}
return 0;
}
Problem I: 素数线性筛 (2113) [21/65]
Tips
不算太难,把洛谷上的代码粘过来改一下范围就可以了。
可以读完范围以后筛出范围内的数,不用输入前就筛好。
Code
#include <stdio.h>
#include <string.h>
#define MAXN 40000001
char prime[MAXN];
int primeList[MAXN],num=0;
void getPrime(int area)
{
memset(prime,1,sizeof(prime));
prime[0]=prime[1]=0;
for(int i=2;i<MAXN;i++)
{
if(prime[i])primeList[num++]=i;
if(num>=area)break;
for(int j=0;j<num&&i*primeList[j]<MAXN;j++)
{
prime[i*primeList[j]]=0;
if(i%primeList[j]==0)break;
}
}
}
int main()
{
int n,q,k;
scanf("%d %d",&n,&q);
getPrime(n);
while(q--)
{
scanf("%d",&k);
printf("%d\n",primeList[k-1]);
}
return 0;
}
Problem J: 五十弦翻塞外声 (1262) [4/20]
Tips
哎呀,真是好诗啊!ヾ(≧▽≦*)o
醉里挑灯看剑,梦回吹角连营。八百里分麾下炙,五十弦翻塞外声,沙场秋点兵。
马作的卢飞快,弓如霹雳弦惊。了却君王天下事,赢得生前身后名。可怜白发生!
咳咳。。。走错片场了
这个题数据范围 1e9,理论上素数筛到 31623 就差不多了,
保险起见多筛一点,反正这筛子是是 O(n) 的,不差这点了。
然后将这个数不断用素数分解,找出它的所有素因子。
样例估计故意不想让你考虑全面,这里另外举个栗子吧:
24 可以拆成 2 2 2 3
其中因子 2 可以取 0,1,2,3 个,3 可以取 0,1 个
那么因子和可以表示为 (20+21+22+23) x (30+31)
代码中将加和的每个素因子放入栈中,最后乘到一起。
这个栈用数组模拟,队列之类的代替也可以,开心就好 (o゚v゚)ノ
更新说明:
2020.02.14 增强数据后只需将 MAXN 改为 1e6 以上即可。
Code
#include <bits/stdc++.h>
using namespace std;
#define MAXN 50000
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()
{
stack<long long>s;
long long yz[10000],yp=0,yznum,sum=0;
getPrime();
long long n;
int t;
scanf("%d",&t);
while(t--)
{
scanf("%lld",&n);
if(n==1)
{
printf("1\n");
continue;
}
yp=0;
for(int i=0;i<num&&primeList[i]<=sqrt(n);i++)
{
if(n%primeList[i]==0)
{
yz[yp++]=primeList[i];
n/=primeList[i];
i=-1;
if(n==1)break;
continue;
}
}
if(n!=1)yz[yp++]=n;
yznum=1;
for(int i=1;i<yp;i++)
{
if(yz[i]==yz[i-1])yznum++;
else
{
sum=0;
for(int j=0;j<=yznum;j++)sum+=pow(yz[i-1],j);
s.push(sum);
yznum=1;
}
}
sum=0;
for(int i=0;i<=yznum;i++)sum+=pow(yz[yp-1],i);
s.push(sum);
sum=1;
while(!s.empty())
{
sum*=s.top();
s.pop();
}
printf("%lld\n",sum);
}
return 0;
}