考前模拟,qbxt十月底day1

立方数(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。

代码:纯暴力
#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
using namespace std;
typedef long long ll;
ll T,x;
map <ll,bool> check;
int main()
{
    freopen("cubic.in","r",stdin);
    freopen("cubic.out","w",stdout);
    scanf("%lld",&T);
    for(ll i=0;i<=1e6;i++) 
    {
        x=i*i*i;check[x]=1;
    }
    for(ll i=1;i<=T;i++) 
    {
        scanf("%lld",&x);
        if(check[x])cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

用二分查找函数会快一点

puts(lower_bound(check, check + 1000000, n) == n ? "YES" : "NO");

或者直接写二分避免卡stl

for(int i = 1; i <= n;i++) {
        int flag = 0;
        ll p = read();
        int l = 1, r = 1000000;
        while(l <= r) {
            int mid = (l + r) >> 1;
            if(a[mid] == p) {
                flag = 1;
                break;
            }
            else if(a[mid] > p) r = mid - 1;
            else l = mid + 1;
        }
        if(flag) puts("YES");
        else puts("NO");
    }

立方数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。

代码:

同t1;需要解释的是题目为了降低难度,给出p一定是质数,根据立方差公式有:
p=x^3-y^3=(x-y)(x^2+xy+y^2)
因为p是质数,根据质数定义,他的因子只有1和他本身,显然后面的式子大于1,所以(x-y)=1,(x^2+xy+y^2)=p;【结论:x=y+1,p=(x^2+xy+y^2)=3y^2+3y+1 , 为质数】

#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
typedef long long ll;
ll T,x,y,z,a;
map <ll,bool> check;
int main()
{
    freopen("cubicp.in","r",stdin);
    freopen("cubicp.out","w",stdout);
    for(ll i=1;i<=999999;i++)
    {
        x=i; y=i+1;
        z=x*x+x*y+y*y;
        check[z]=1;
    }
    scanf("%lld",&T);
    for(ll i=1;i<=T;i++)
    {
        scanf("%lld",&a);
        if(check[a]==1) puts("YES");
        else puts("NO");
    }
    return 0;
}
还是二分查找比较快,详见t1

猜数字(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;
}

总不能水一天吧,

所以长者就出了这么一个鬼畜t,让我卡了一下午才想过来;思路是二分+并查集(也可以用暴力模拟代替);
具体的:1。二分答案
2.把xi由大到小排序,那么就有(i > i-1,a[i] <= a[i-1])①a[i] < a[i-1]时,若新加入的线段(x~y)在之前已经被完全覆盖,则矛盾;②当a[i] = a[i-1]若两线段区间没有交集,则矛盾(因为有n个不同的数);
3.并查集操作f[]的代表元素是当前线段集合的最右点的再右一个,即rmax+1;处理并查集时,就看代表元素是否覆盖与否
4.lmin~rmax——并集;lmax~rmin——交集;

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=1000000+10;
int T,n,li,ri,mid,ans,f[maxn],lmin,lmax,rmin,rmax;
struct node
{
    int x,y,w;
}p[maxn],t[maxn];
inline int read()
{
    int g=1,s=0;    char ch=getchar();
    while(ch>'9'||ch<'0'){ if(ch=='-') g=-1; ch=getchar();}
    while(ch<='9'&&ch>='0'){ s=(s<<3)+(s<<1)+ch-'0'; ch=getchar();}
    return g*s;
}
bool cmp(node a,node b)
{
    return a.w>b.w;
}
int find(int now)
{
    return now==f[now]?now:f[now]=find(f[now]);
}
bool check(int midd)
{
    for(int i=1;i<=n+1;i++) f[i]=i;//之后要把代表元素设成右边一位,所以n+1 
    for(int i=1;i<=midd;i++) t[i]=p[i];
    sort(t+1,t+1+midd,cmp);
    lmin = lmax = t[1].x;   rmin = rmax = t[1].y;//先把第一个放出来 
    for(int i=1;i<=midd;i++)
    {
        if(t[i].w < t[i-1].w)
        {
            if(find(lmax) > rmin) return true;//注意有后效性 
            for(int j=find(lmin);j<=rmax;j++)
            f[find(j)] = find(rmax+1);//把区间代表元素设到rmax+1位
            lmin = lmax =t[i].x;    rmin = rmax = t[i].y;//后效性到for i+1是才会用到 
        }
        else //t[i].w == t[i-1].w
        {
            lmin = min(lmin,t[i].x);    lmax = max(lmax,t[i].x);
            rmin = min(rmin,t[i].y);    rmax = max(rmax,t[i].y);
            if(rmin < lmax) return true;
        }
    }
    if(find(lmax) > rmin) return true;//后效性 QAQ 
    return false;
}
int main()
{
    n=read();   T=read();
    for(int i=1;i<=T;i++) p[i].x=read(), p[i].y=read(), p[i].w=read();
    li=1,ri=T,ans=T+1;
    while(li<=ri)
    {
        mid=(ri+li)>>1;
        if(check(mid))  ans=mid,ri=mid-1;
        else li=mid+1;
    }
    printf("%d",ans);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值