立方数(cubic)
Time Limit:1000ms Memory Limit:128MB
题目描述
LYK定义了一个数叫“立方数”,若一个数可以被写作是一个正整数的3次方,则这个数就是立方数,例如1,8,27就是最小的3个立方数。
现在给定一个数P,LYK想要知道这个数是不是立方数。
当然你有可能随机输出一些莫名其妙的东西来骗分,因此LYK有T次询问~
输入格式(cubic.in)
第一行一个数T,表示有T组数据。
接下来T行,每行一个数P。
输出格式(cubic.out)
输出T行,对于每个数如果是立方数,输出“YES”,否则输出“NO”。
输入样例
3
8
27
28
输出样例
YES
YES
NO
数据范围
对于30%的数据p<=100。
对于60%的数据p<=10^6。
对于100%的数据p<=10^18,T<=100。
题解
p<=10^18,p=x^3
x<=10^6
暴力枚举。
甚至都不用排序,O(Tx)都能过
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int t,ans[250];
struct node{
int id;
long long num;
}tmp[251];
bool cmp(node a,node b){
return a.num<b.num;
}
int main(){
freopen("cubic.in","r",stdin);
freopen("cubic.out","w",stdout);
scanf("%d",&t);
for(int i=1;i<=t;i++){
scanf("%lld",&tmp[i].num);
tmp[i].id=i;
}
sort(tmp+1,tmp+t+1,cmp);
int cnt=1;
for(long long i=1;;i++){
long long p=i*i*i;
while(cnt<=t&&p>tmp[cnt].num){
cnt++;
}
if(cnt>t) break;
if(p==tmp[cnt].num){
ans[tmp[cnt].id]=1;
cnt++;
if(cnt>t) break;
while(cnt<=t&&tmp[cnt].num==tmp[cnt-1].num){
ans[tmp[cnt].id]=1;
cnt++;
}
}
}
for(int i=1;i<=t;i++){
if(ans[i]){
printf("YES\n");
}else printf("NO\n");
}
}
立方数2(cubicp)
Time Limit:1000ms Memory Limit:128MB
题目描述
LYK定义了一个数叫“立方数”,若一个数可以被写作是一个正整数的3次方,则这个数就是立方数,例如1,8,27就是最小的3个立方数。
LYK还定义了一个数叫“立方差数”,若一个数可以被写作是两个立方数的差,则这个数就是“立方差数”,例如7(8-1),26(27-1),19(27-8)都是立方差数。
现在给定一个数P,LYK想要知道这个数是不是立方差数。
当然你有可能随机输出一些莫名其妙的东西,因此LYK有T次询问~
这个问题可能太难了…… 因此LYK规定P是个质数!
输入格式(cubicp.in)
第一行一个数T,表示有T组数据。
接下来T行,每行一个数P。
输出格式(cubicp.out)
输出T行,对于每个数如果是立方差数,输出“YES”,否则输出“NO”。
输入样例
5
2
3
5
7
11
输出样例
NO
NO
NO
YES
NO
数据范围
对于30%的数据p<=100。
对于60%的数据p<=10^6。
对于100%的数据p<=10^12,T<=100。
题解
初中数学专场:p=a^3-b^3=(a-b)(a^2+a*b+b^2) a>=1,b>=1
因为p是质数,因子只有1和它本身,显然(a^2+a*b+b^2)!=1,那么a-b=1;
p<10^12 a<10^6
暴力枚举a。
O(Tx)也能过
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int t,ans[251];
struct node{
int id;
long long num;
}tmp[251];
bool cmp(node a,node b){
return a.num<b.num;
}
int main(){
freopen("cubicp.in","r",stdin);
freopen("cubicp.out","w",stdout);
scanf("%d",&t);
for(int i=1;i<=t;i++){
scanf("%lld",&tmp[i].num);
tmp[i].id=i;
}
sort(tmp+1,tmp+t+1,cmp);
int cnt=1;
for(long long i=1;;i++){
long long j=i+1;
long long p=i*i+j*j+j*i;
while(cnt<=t&&p>tmp[cnt].num){
cnt++;
}
if(cnt>t) break;
if(p==tmp[cnt].num){
ans[tmp[cnt].id]=1;
cnt++;
if(cnt>t) break;
while(cnt<=t&&tmp[cnt].num==tmp[cnt-1].num){
ans[tmp[cnt].id]=1;
cnt++;
}
}
}
for(int i=1;i<=t;i++){
if(ans[i]){
printf("YES\n");
}else printf("NO\n");
}
return 0;
}
T1,T2题解
暴力枚举
sort+枚举
二分(应该是最快)
setO(x*logx)一遍插入,O(Tlogx)查询,不会T,但是极慢
set的基本操作
s.insert(a);插入a
s.find(a);查询有无a这个数;如果有,返回迭代器,如果没有,返回s.end()
猜数字(number)
Time Limit:2000ms Memory Limit:128MB
题目描述
LYK在玩猜数字游戏。
总共有n个互不相同的正整数,LYK每次猜一段区间的最小值。形如[li,ri]这段区间的数字的最小值一定等于xi。
我们总能构造出一种方案使得LYK满意。直到…… LYK自己猜的就是矛盾的!
例如LYK猜[1,3]的最小值是2,[1,4]的最小值是3,这显然就是矛盾的。
你需要告诉LYK,它第几次猜数字开始就已经矛盾了。
输入格式(number.in)
第一行两个数n和T,表示有n个数字,LYK猜了T次。
接下来T行,每行三个数分别表示li,ri和xi。
输出格式(number.out)
输出一个数表示第几次开始出现矛盾,如果一直没出现矛盾输出T+1。
输入样例
20 4
1 10 7
5 19 7
3 12 8
1 20 1
输出样例
3
数据范围
对于50%的数据n<=8,T<=10。
对于80%的数据n<=1000,T<=1000。
对于100%的数据1<=n,T<=1000000,1<=li<=ri<=n,1<=xi<=n(但并不保证一开始的所有数都是1~n的)。
Hint
建议使用读入优化
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
return x * f;
}
题解
在线oj
https://www.luogu.org/problemnew/show/2898
oj上全部正确输出0,和考题略有不同
二分+并查集验证
类似数轴染色
二分到哪一句为真,
按x从大到小排序
fa[i]表示与i在同一集合内的最左的坐标-1(-1可以避免处理< 2,2 >这样的区间)
fa[i]+1–i属于同一集合
检查当前区间是否已经在同一集合内,if(fa[r]<l)
说明区间< l,r >在同一集合内
若在,则当前区间已经被另一个更大的x’合并过,与当前区间最小值是x矛盾
若不在,则合并当前区间
注意:当x相同,区间不同时,如果两区间不重合,不符合数都不相等的条件
检查是否矛盾时,用区间的交,因为最小值存在于区间的交之中。
合并时,用区间的并,因为这个大区间的最小值是x
细节处理见代码
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1000000+500;
int fa[N],p[N];
struct node{
int l,r,x;
}a[N];
int n,t;
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
return x * f;
}
bool cmp(int x,int y){
return a[x].x>a[y].x;
}
void init(int x){
for(int i=1;i<=n+5;i++) fa[i]=i;
for(int i=1;i<=x;i++) p[i]=i;
sort(p+1,p+x+1,cmp);
p[x+1]=0;
}
int find(int x){
if(x==fa[x]) return x;
else return fa[x]=find(fa[x]);
}
void merge(int l,int r){
int f=find(l-1);//将l,r的fa数组修改为l-1
for(int i=r;i>=l;i--){
int tmp=find(i);
fa[find(i)]=f;
i=tmp;//直接跳到原来的find(i) 比暴力修改更快
}
return ;
}
bool check(int x){
init(x);
int lmax,lmin,rmax,rmin;
//处理x相同的区间时,需要维护的左右端点值 <lmin,rmax>是区间并 <lmax,rmin>是区间交
lmax=lmin=a[p[1]].l;
rmax=rmin=a[p[1]].r;
for(int i=2;i<=x;i++){
int c=p[i],d=p[i-1];
if(a[c].x!=a[d].x){//这时的lr是i-1的lr
if(find(rmin)<lmax) return 0;
merge(lmin,rmax);
lmax=lmin=a[c].l;//将l,r移动到当前区间
rmax=rmin=a[c].r;//
}else {
if(a[c].x==a[d].x){//如果出现x相等的情况
lmax=max(lmax,a[c].l);//更新
lmin=min(lmin,a[c].l);
rmax=max(rmax,a[c].r);
rmin=min(rmin,a[c].r);
if(rmin<lmax) return 0;//区间没有交集,不符合题目中数字互不重复的条件
if(find(rmin)<lmax) return 0;//检查区间交是否在同一集合内
}
}
}
if(find(rmin)<lmax) return 0;//检查最后一个区间
return 1;
}
int main(){
freopen("number.in","r",stdin);
freopen("number.out","w",stdout);
n=read(),t=read();
for(int i=1;i<=t;i++)
a[i].l=read(),a[i].r=read(),a[i].x=read();
int l=-1,r=t+1;
while(r-l>1){
int mid=r+l>>1;
if(check(mid)) l=mid;
else r=mid;
}
//if(r==t+1) r=0;
printf("%d",r);
return 0;
}