洛谷P4774 [NOI2018]屠龙勇士

题目大意:

这个题面和数据范围不太好粘,自己看吧……

首先我们应该可以看出这是一道(excrt)题目

至于剑这个限制其实很(naive),用(multiset)存一下就好了

根据题意我们可以列出方程组

[egin{cases}d_1xequiv a_1 (mod p_1)\d_2xequiv a_2 (mod p_2)\……\d_nxequiv a_n (mod p_n)end{cases} ]

其中(d_i)为剑攻击力,(x)为攻击次数,(a_i)为龙龙的血量,(p_i)为回复能力

毒瘤

但是我们好像有(a_i>p_i)的情况……根据题目我们好像不能直接模掉……

然而我们翻过题解之后发现可能存在(a_i>p_i)时,全部满足(p_i=1)那么我们大力判断掉就好了

具体方法:

[ans=max{ lceilfrac{d_i}{a_i} ceil } ]

通解

先考虑(d_ixequiv a_i (mod p_i))好像和一般的(crt)方程不太一样,化简一下

[x*d_i+y*p_i=- a_i ]

(exgcd)求出一组(x_t,y_t)

由于(ecgcd)通解为(x=x_t+k*frac{b}{gcd(a,b)}),得到(x=x_t+k*frac{p_i}{gcd(p_i,d_i)})

(frac{p_i}{gcd(p_i,d_i)})取模,得到

(xequiv x_t (mod frac{p_i}{gcd(p_i,d_i)}))

然后大力(excrt)

注意

我们感性理解一下可以得出(xge (maxn=max{lceilfrac{a_i}{d_i} ceil})),如果最后答案小于这个数,应该补上

推出来是(ret=ret+m*lceilfrac{maxn-ret}{m} ceil)

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define eps (1e-8)
	inline int read()
	{
		int x=0;char ch,f=1;
		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
		if(ch=='-') f=0,ch=getchar();
		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
		return f?x:-x;
	}
	const int N=1e5+10;
	int haku;
	int n,m;
	int a[N],p[N],sword[N];
	inline void exgcd(int &x,int &y,int &g,int a,int b)
	{
		if(!b){x=1,y=0,g=a;return;}
		exgcd(y,x,g,b,a%b);
		y-=a/b*x;
	}
	inline int slow(int x,int k,int p)
	{
		int ret=0;
		while(k)
		{
			if(k&1) ret=(ret+x)%p;
			x=(x+x)%p;
			k>>=1;
		}
		return ret;
	}
	multiset<int> q;
	multiset<int>::iterator it;
	inline int excrt()
	{
		int m=1,ret=0,maxn=0,x,y,g;
		for(int i=1;i<=n;++i)
		{
			it=q.upper_bound(a[i]);
			if(it!=q.begin()) --it;
			int k=*it;
			q.erase(it);
			q.insert(sword[i]);
			maxn=max(maxn,(a[i]-1)/k+1);
			k%=p[i],a[i]%=p[i];
			exgcd(x,y,g,k,p[i]);
			if(a[i]%g) return -1;
			p[i]/=g;
			a[i]=slow(a[i]/g,(x%p[i]+p[i])%p[i],p[i]);
			int c=((a[i]-ret)%p[i]+p[i])%p[i];
			exgcd(x,y,g,m,p[i]);
			if(c%g) return -1;
			x=slow(x,c/g,p[i]);
			ret+=x*m;
			m*=p[i]/g;
			ret%=m;
		}
		return ret>=maxn?ret:ret+m*((maxn-ret-1)/m+1);
	}
	inline void main()
	{
		haku=read();
		while(haku--)
		{
			n=read(),m=read();
			for(int i=1;i<=n;++i) a[i]=read();
			for(int i=1;i<=n;++i) p[i]=read();
			for(int i=1;i<=n;++i) sword[i]=read();
			for(int i=1;i<=m;++i) q.insert(read());
			printf("%lld
",excrt());
			q.clear();
		}
	}
}
signed main()
{
	red::main();
	return 0;
}
原文地址:https://www.cnblogs.com/knife-rose/p/12058420.html