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; }