比赛链接:
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;
}