HDU 5976 逆元+打表+莫队
2017-09-18 14:10
375 查看
题意
给一个数,拆分成不同的数,使得乘积最大。题解
我们可以观察一下如何拆分乘积最大,可以发现从2开始均分。如果最后有剩余的元素,均分到每一个元素1个值,如果还有剩余(只可能剩余1个),分给最后一个元素。暴力交一发,TLE。
这样的话,我们再次分析这个问题,我们发现拆分后的元素分为两部分(很明显就能看出来),于是这个问题就转化成了区间问题。给你二组区间,问这两组区间的乘积是多少。很明显,莫队可以解决这个问题。
莫队交一发,TLE。
我们再次分析这个问题,我们发现事实上莫队还不够好,我们发现1-1e9这个区间恰好能一次均分的元素个数不超过10^5个,于是我们把10^5个元素算出来,这样的话,我们在莫队转移的时候就多了很多元素可以利用。对于每个查询,我们首先将状态转移到最近的一个均分之后最大元素为当前状态最大元素的状态。然后剔除掉那些不存在的元素。不存在元素的数量是非常少的,我们可以认为剔除过程是O(1)的。这样的话,总体复杂度O(N)。
代码
#include<bits/stdc++.h> #define LL long long #define UP(i,l,h) for(int i=l;i<h;i++) #define DOWN(i,h,l) for(int i=h-1;i>=l;i--) #define W(t) while(t) #define MEM(a,b) memset(a,b,sizeof(a)) #define MAXN 1000010 #define BUF 25001000 #define MOD 1000000007 #define INF 0x3f3f3f3f using namespace std; LL mp[MAXN]; LL multi[MAXN]; struct Node { int id,x,alt,art,blt,brt; LL ans; }; Node nodes[MAXN]; LL exgcd(LL a,LL b,LL &x,LL &y){ if(b==0){ x=1,y=0; return a; } LL ans=exgcd(b,a%b,x,y); LL temp=x; x=y; y=temp-(a/b)*y; return ans; } LL inv(LL a){ LL x,y; LL t=exgcd(a,MOD,x,y); if(t!=1) return -1; return (x%MOD+MOD)%MOD; } int main() { // freopen("d://input.txt","r",stdin); // freopen("d://out1.txt","w",stdout); int sum=0; MEM(mp,0); UP(i,2,100010) { sum+=i; mp[i]=sum; } multi[1]=1; UP(i,2,100010) { multi[i]=(multi[i-1]*i)%MOD; } int t; scanf("%d",&t); UP(i,0,t) { nodes[i].id=i; scanf("%d",&nodes[i].x); if(nodes[i].x<5){ printf("%d\n",nodes[i].x); continue; } int pos=upper_bound(mp,mp+50010,nodes[i].x)-mp-1; nodes[i].alt=nodes[i].art=nodes[i].blt=nodes[i].brt=1; if(nodes[i].x==mp[pos]) { nodes[i].alt=2,nodes[i].art=pos; } else if(nodes[i].x<mp[pos]+pos-1) { nodes[i].alt=2,nodes[i].art=pos-(nodes[i].x-mp[pos]); nodes[i].blt=pos+2-(nodes[i].x-mp[pos]),nodes[i].brt=pos+1; } else if(nodes[i].x==mp[pos]+pos-1) { nodes[i].blt=3,nodes[i].brt=pos+1; } else if(nodes[i].x==mp[pos]+pos) { nodes[i].alt=3,nodes[i].art=pos; nodes[i].blt=pos+2,nodes[i].brt=pos+2; } // cout<<nodes[i].alt<<" "<<nodes[i].art<<" "<<nodes[i].blt<<" "<<nodes[i].brt<<endl; LL ans=multi[max(nodes[i].art,nodes[i].brt)]; // cout<<ans<<endl; DOWN(j,nodes[i].blt,nodes[i].art+1) ans=(ans*inv(j))%MOD; DOWN(j,nodes[i].alt,2) ans=(ans*inv(j))%MOD; printf("%I64d\n",ans); } }
相关文章推荐
- hdu 5976 Detachment 逆元+打表
- [HDU-5976] [Problem F](逆元+二分优化+数学分析)
- HDU 5976 逆元
- HDU 5976 Detachment 打表找规律
- hdu 5976 Detachment 逆元+二分+数学
- HDU 5976 Detachment(逆元+二分优化+数学分析)
- Hdu 5793 A Boring Question【暴力打表+找规律+求逆元+快速幂+快速积】
- HDU - 5976 Detachment (逆元)
- 打表找规律+快速幂+求逆元______A Boring Question(hdu 5793 2016多校第六场)
- HDU 5976 贪心+逆元
- HDU 5976 Detachment (逆元)
- HDU - 5976 Detachment(ICPC2016 大连现场,脑洞加逆元)
- HDU 5976 Detachment (数学规律+逆元)
- HDU 5976 Detachment(逆元)+逆元总结
- ☆HDU 5976 Detachment 详细题解(贪心+逆元+前缀和,积)
- 【HDU】3944 - DP?(Lucas & 逆元 & 大组合数 & 打表)
- hdu 5976 Detachment(逆元+贪心+数论+前缀和+二分 待整理)
- hdu 5976(数论、前缀和、前缀积、逆元)
- HDU 4828 (卡特兰数+逆元)
- HDU 5651 逆元