2019杭电多校训练(四)

比赛链接:

http://acm.hdu.edu.cn/search.php?field=problem&key=2019+Multi-University+Training+Contest+4&source=1&searchmode=source

hdu6623

题意:

把一个数转化成质因数加指数连乘的形式,求最小指数

分析:

当时我们考虑先筛出$1e18^{\frac{1}{4}}$的所有素数,复杂度大概在$2e8$左右,刚好被卡了

其实筛到$1e18^{\frac{1}{5}}$的情况也不是很复杂(当时以为四个因数太复杂了,没敢写)

把小于$1e18^{\frac{1}{5}}$的质因子去掉,剩下的最多有四个质因子

如果M可以开四次根,那么M一定是qqqq的形式

如果M可以开三次根,那么M一定是qqq的形式

如果M可以开二次根,那么M一定是qq或者qqpp形式

否则M一定存在一次幂

ac代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e6 + 5;
const ll mod = 1e9 + 7;
int vis[maxn],prim[maxn],top;
bool check(ll x,int y)//判断x能否开y次幂
{

    ll st=1,en=pow(1e18,1.0/y)+1;
    while(st!=en){
        ll md=(st+en)/2;
        ll res=1;
        for(int i=1;i<=y;i++)res*=md;
        if(res>=x)en=md;
        else st=md+1;
    }
    ll res=1;
    for(int i=1;i<=y;i++)res*=st;
    if(res==x)return 1;
    else return 0;
}

int main()
{
   // cout<<check(8,3)<<endl;
    for(int i=2;i<=4000;i++){
        if(vis[i]==0){
            prim[++top]=i;
            //cout<<i<<endl;
            for(int j=2*i;j<=4000;j+=i)
                vis[j]=1;
        }
    }
    int T;
    scanf("%d",&T);
    while(T--){
        int ans=70;
        ll n;
        scanf("%lld",&n);
        for(int i=1;i<=top;i++){
            if(n%prim[i]==0){
                int res=0;
                while(n%prim[i]==0)n/=prim[i],res++;
                ans=min(res,ans);
                if(ans==1)break;
            }
        }
        if(n==1||ans==1){
            printf("%d\n",ans);
            continue;
        }
        if(check(n,4))ans=min(ans,4);
        else if(check(n,3))ans=min(ans,3);
        else if(check(n,2))ans=min(ans,2);
        else ans=1;
        printf("%d\n",ans);
    }
    return 0;
}

hdu6621

题意:

给出$n$个数,和$m$次询问

每次询问是一段区间中,所有数与$p$的差值的第$k$大

分析:

二分答案再主席树验证

现在才真正理解主席树的含义,就是保存了$n$棵区间和的线段树

既可以求第$k$大也可以求出某段区间数的数量

ac代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=1e5+5;
struct Tree
{
     int L,R,num;
}tree[maxn*25];
int root[maxn];
int cnt;
void updata(int x,int &rt,int a,int b)
{
     tree[cnt++]=tree[rt];
     rt=cnt-1;
     tree[rt].num++;
     if(a==b)return;
     int mid=(a+b)/2;
     if(x>=mid+1)
         updata(x,tree[rt].R,mid+1,b);
     else
         updata(x,tree[rt].L,a,mid);
}
int quer(int l,int r,int a,int b,int st,int en)//quer(root[l-1],root[r],r-l+1-mid,1,n)
{
    if(a>en||b<st)return 0;
    if(a<=st&&b>=en)return tree[r].num-tree[l].num;
    int md=(st+en)/2;
    return quer(tree[l].L,tree[r].L,a,b,st,md)+quer(tree[l].R,tree[r].R,a,b,md+1,en);
}
int main()
{
    int n,m,T;
    scanf("%d",&T);
    while(T--)
    {
        for(int i=0;i<maxn*25;i++)tree[i].num=0;
        scanf("%d %d",&n,&m);
        cnt=1;
        for(int i=1;i<=n;i++)
        {
            root[i]=root[i-1];
            int x;
            scanf("%d",&x);
            updata(x,root[i],1,1e6);
        }
//        cout<<quer(root[1],r,1,1,1,1e6)<<endl;
        int ans=0;
        for(int i=1;i<=m;i++)
        {
            int l,r,p,k;
            scanf("%d %d %d %d",&l,&r,&p,&k);
            l^=ans,r^=ans,p^=ans,k^=ans;
            int st=0,en=1e6;
            while(st!=en){
                int md=(st+en)/2;
                if(quer(root[l-1],root[r],max(1,p-md),min(1000000,md+p),1,1e6)>=k)en=md;
                else st=md+1;
            }
            ans=st;
            printf("%d\n",st);
        }
    }
    return 0;
}

  

转载于:https://www.cnblogs.com/carcar/p/11290006.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值