zoukankan      html  css  js  c++  java
  • BZOJ5418[Noi2018]屠龙勇士——exgcd+扩展CRT+set

    题目链接:

    [Noi2018]屠龙勇士

    题目大意:有$n$条龙和初始$m$个武器,每个武器有一个攻击力$t_{i}$,每条龙有一个初始血量$a_{i}$和一个回复值$p_{i}$(即只要血量为负数就一直回复$p_{i}$的血量,只有在攻击后会回血),杀死一条龙当且仅当攻击结束后或回复血量之后血量为$0$,杀死一条龙会获得一个新的武器。现在要求对每条龙攻击固定次数$x$求出最小的$x$,使所有龙都能被杀死。

    因为每次选择的武器是固定的,所以只要用$multiset$存当前剩下的武器然后每次按题目规则取即可。设攻击第$i$条龙的武器攻击力为$ti$,那么可以得到$n$个不定方程$x*t_{i}-k*p_{i}=a_{i}$。对于每个不定方程因为$p_{i}$与$t_{i}$不一定互质,所以求出$d=gcd(p_{i},t_{i})$并将等式两边都除掉$d$(如果$a_{i}$不能整除$d$则无解)。这样每个方程就能用$exgcd$解出最小的非负整数解$x_{i}$,那么显然$xequiv x_{i}(mod frac{p_{i}}{d})$。由此得到了$n$个方程的同余方程组(设每个同余方程的模数为$m_{i}$,即为上面的$frac{p_{i}}{d}$),由于模数不一定互质,所以要用扩展CRT来求出最小的$x$。因为要保证攻击能将每条龙打到至少$0$血,即$x*t_{i}>=a_{i}$,所以要求出将每条龙打到$0$血或往下的最小次数的最大值$mx$,只要$x$小于$mx$就不停地给$x$加上$lcm(m_{1},m_{2}...m_{n})$。

    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<bitset>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    #define INF 4e18+10
    using namespace std;
    ll c1,m1,c2,m2;
    int N,M,T;
    ll mx,x;
    ll lcm;
    multiset<ll>s;
    multiset<ll>::iterator it;
    ll a[100010];
    ll p[100010];
    ll b[100010];
    ll t[100010];
    ll c[100010];
    ll m[100010];
    ll quick(ll x,ll y,ll mod)
    {
    	ll res=0ll;
    	while(y)
    	{
    		if(y&1)
    		{
    			res=(res+x)%mod;
    		}
    		y>>=1;
    		x=(x+x)%mod;
    	}
    	return res;
    }
    ll gcd(ll x,ll y)
    {
    	return y==0?x:gcd(y,x%y);
    }
    void exgcd(ll a,ll b,ll &x,ll &y)
    {
    	if(!b)
    	{
    		x=1;y=0;
    		return ;
    	}
    	exgcd(b,a%b,y,x);
    	y-=(a/b)*x;
    }
    ll inv(ll n,ll mod)
    {
    	ll x,y;
    	exgcd(n,mod,x,y);
    	return (x%mod+mod)%mod;
    }
    int main()
    {
    	scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%d%d",&N,&M);
    		s.clear();
    		mx=0;
    		for(int i=1;i<=N;i++)
    		{
    			scanf("%lld",&a[i]);
    		}
    		for(int i=1;i<=N;i++)
    		{
    			scanf("%lld",&p[i]);
    		}
    		for(int i=1;i<=N;i++)
    		{
    			scanf("%lld",&t[i]);
    		}
    		for(int i=1;i<=M;i++)
    		{
    			scanf("%lld",&x);
    			s.insert(x);
    		}
    		for(int i=1;i<=N;i++)
    		{
    			it=s.upper_bound(a[i]);
    			if(it!=s.begin())
    			{
    				it--;
    			}
    			b[i]=*it;
    			s.erase(it);
    			s.insert(t[i]);
    		}
    		bool flag=false;
    		for(int i=1;i<=N;i++)
    		{
    			mx=max(mx,(a[i]-1)/b[i]+1);
    			ll d=gcd(b[i],p[i]);
    			if(a[i]%d)
    			{
    				flag=true;
    				break;
    			}
    			ll x,y;
    			exgcd(b[i]/d,p[i]/d,x,y);
    			ll P=p[i]/d;
    			x=quick(x,a[i]/d,P);
    			x=(x%P+P)%P;
    			c[i]=x;
    			m[i]=P;
    		}
    		if(flag)
    		{
    			printf("-1
    ");
    			continue;
    		}
    		flag=false;
    		m1=m[1],c1=c[1];
    		for(int i=2;i<=N;i++)
    		{
    			c2=c[i],m2=m[i];
    			ll d=gcd(m1,m2);
    			if((c2-c1)%d)
    			{
    				flag=true;
    				break;
    			}
    			ll g=inv(m1/d,m2/d);
    			ll sum=quick((c2-c1)/d,g,m2/d);
    			ll mod=quick(m1,m2/d,INF);
    			sum=quick(sum,m1,mod);
    			sum+=c1,sum%=mod;
    			c1=sum,m1=mod;
    		}
    		if(flag)
    		{
    			printf("-1
    ");
    			continue;
    		}
    		c1=(c1%m1+m1)%m1;
    		ll ans=1ll;
    		for(int i=1;i<=N;i++)
    		{
    			ll d=gcd(ans,m[i]);
    			ans=quick(ans/d,m[i],INF);
    		}
    		if(c1>=mx)
    		{
    			printf("%lld
    ",c1);
    			continue;
    		}
    		ll res=ceil((double)(mx-c1)/ans);
    		c1+=quick(ans,res,INF);
    		printf("%lld
    ",c1);
    	}
    }
  • 相关阅读:
    【转】十分钟了结MySQL information_schema
    【转】CentOS6.5下Redis安装与配置
    java知识点
    【转】STRING使用EQUALS方法和==分别比较的是什么
    【转】JVM性能调优监控工具jps、jstack、jmap、jhat、jstat、hprof使用详解
    【转】mybatis入门基础(六)----高级映射(一对一,一对多,多对多)
    【转】mybatis中的#和$的区别
    【转】HashMap
    【转】@Transactional事务几点注意
    关于PC端的密码框自动获取浏览器保存密码的问题[vue]
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/10385814.html
Copyright © 2011-2022 走看看