您的位置:首页 > 其它

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);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: