联考20200607 T1 随机除法

题目:


分析:
啊,范围是(1e24),出题人身体健康冚家富贵嗷
不敢用__int128,手写高精度(
考虑(N=prod_{i=1}^{m}p_i^{k_i})
不难发现最后的答案只与(k)有关,尝试期望(dp)

前缀和优化一下
状态(K)由状态(K')转来,(K)(K')只有一位差距1
我们暴力搜索最大的状态,明显是由最小的质数构成,且(N)最多只会有20个质因数
两个状态如果排序后相同,这两个状态的值就会相同(每一位等价)
直接将搜索出来的状态哈希或者直接加入map查询
然后就暴力预处理所有状态了
复杂度玄学,不过爆搜出的状态数级别是(1e5),预处理卡着时间过(

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<iostream>
#include<map>
#include<bitset>
#include<string>

#define maxn 200005
#define K 20
#define MOD 1000000007
#define maxm 105

using namespace std;

const long long D=1000000ll*1000000ll;

inline long long getint()
{
	long long num=0,flag=1;char c;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
	return num*flag;
}

map<int,int>M;
int ans[maxn],sum[maxn][21];
int cnt,tot,pri[maxm],f[maxm];
char s[maxm];
inline bool cmp(int x,int y){return x>y;}
inline int upd(int x){return x<MOD?x:x-MOD;}
struct BIGNUM{
	long long p[2];
	inline void getnum(long long x)
	{p[0]=p[1]=0,p[0]=x/D,p[1]=x%D;}
	friend BIGNUM operator *(BIGNUM x,long long y)
	{
		x.p[0]*=y,x.p[1]*=y,x.p[0]+=x.p[1]/D,x.p[1]%=D;
		return x;
	}
	friend bool operator <(BIGNUM x,BIGNUM y)
	{
		return x.p[0]==y.p[0]?x.p[1]<y.p[1]:x.p[0]<y.p[0];
	}
	friend bool operator <=(BIGNUM x,BIGNUM y)
	{
		return x.p[0]==y.p[0]?x.p[1]<=y.p[1]:x.p[0]<y.p[0];
	}
	friend BIGNUM operator /(BIGNUM x,long long y)
	{
		x.p[1]+=x.p[0]%y*D,x.p[0]/=y,x.p[1]/=y;
		return x;
	}
	friend long long operator %(BIGNUM x,long long y)
	{
		x.p[1]+=x.p[0]%y*D;
		return x.p[1]%y;
	}
}N;
pair<BIGNUM,vector<int> >p[maxn];
vector<int>d;

inline int ksm(int num,int k)
{
	int ret=1;
	for(;k;k>>=1,num=1ll*num*num%MOD)if(k&1)ret=1ll*ret*num%MOD;
	return ret;
}
inline int solve(vector<int>a,int p)
{
	while(p<K&&a[p]<a[p+1])swap(a[p],a[p+1]),p++;
	int ans=0;
	for(int i=0,sz=a.size();i<sz;i++)ans=ans*MOD+a[i];
	return M[ans];
}
inline int getans(vector<int>a)
{
	sort(a.begin()+1,a.end(),cmp);
	int ans=0;
	for(int i=0,sz=a.size();i<sz;i++)ans=ans*MOD+a[i];
	return M[ans];
}
inline void init()
{
	for(int i=2;i<=100;i++)
	{
		if(!f[i])pri[++tot]=f[i]=i;
		for(int j=1;j<=tot&&pri[j]<=f[i];j++)
		{
			int tmp=pri[j]*i;
			if(tmp>100)break;
			f[tmp]=pri[j];
		}
	}
}

inline void work(BIGNUM now,int pos,int x)
{
	p[++cnt]=make_pair(now,d);
	for(int i=1;i<=x&&now*pri[pos]<=N;i++)
		now=now*pri[pos],d[pos]=i,work(now,pos+1,i),d[pos]=0;
}

int main()
{
	init(),N.getnum(1);
	for(int i=1;i<=24;i++)N=N*10;
	d.resize(K);
	BIGNUM num;num.getnum(1);
	work(num,1,100);
	sort(p+1,p+cnt+1);
	for(int i=1;i<=cnt;i++)
	{
		long long val=0;
		for(int j=0,sz=p[i].second.size();j<sz;j++)val=val*MOD+p[i].second[j];
		M[val]=i;
	}
	ans[1]=0;
	for(int i=0;i<=K;i++)sum[1][i]=0;
	for(int i=2;i<=cnt;i++)
	{
		for(int j=K-1;j>=0;j--)
		{
			sum[i][j]=sum[i][j+1];
			if(p[i].second[j])
			{
				vector<int>tmp=p[i].second;tmp[j]--;
				sum[i][j]=upd(sum[i][j]+sum[solve(tmp,j)][j]);
			}
		}
		int tmp=1;
		for(int j=0,sz=p[i].second.size();j<sz;j++)tmp=1ll*tmp*(p[i].second[j]+1)%MOD;
		ans[i]=1ll*(sum[i][0]+tmp)*ksm(tmp-1,MOD-2)%MOD;
		for(int j=0;j<=K;j++)sum[i][j]=upd(sum[i][j]+ans[i]);
	}
	BIGNUM n;
	while(~scanf("%s",s))
	{
		int tmp=strlen(s);
		for(int i=tmp-1;~i;i--)s[25-tmp+i]=s[i];
		for(int i=0;i<25-tmp;i++)s[i]='0';
		long long pw=D/10;
		n.getnum(0);
		for(int i=13;i<25;i++)n.p[1]+=1ll*pw*(s[i]-48),pw/=10;
		pw=D;
		for(int i=0;i<13;i++)n.p[0]+=1ll*pw*(s[i]-48),pw/=10;
		int m=getint();
		vector<int>a;
		a.resize(1);
		for(int i=1;i<=m;i++)
		{
			int x=getint(),cnt=0;
			while(n%x==0)cnt++,n=n/x;
			a.push_back(cnt);
		}
		a.resize(K);
		printf("%d
",ans[getans(a)]);
	}
}

原文地址:https://www.cnblogs.com/Darknesses/p/13068615.html