• [NOI2018] 屠龙勇士


    前言

    属实是板题了,竟然没做过,本想rush一波结果怎么都过不了样例,然后去模板那里测发现也过不了样例,看半天原来是板子写挂了,相当尴尬。

    题目

    洛谷

    讲解

    由于 打着太麻烦,所以下文直接用 = 了。

    可以发现每头龙对应的剑是唯一确定的,所以用 \(\operatorname{multiset}\) 直接求出所有龙对应的剑,记其攻击力为 \(A_i\)

    然后我们观察一下数据范围,当不满足 \(a_i\le p_i\) 时,一定有 \(p_i=1\),此时答案为 \(\max\{\lceil\frac{a_i}{A_i}\rceil\}\),至于为什么出题人这么设计,我们接下来马上解答。

    现在考虑 \(a_i\le p_i\) 的情况,我们其实是要求方程组 \(A_iX=a_i\pmod {p_i}\) 的解,可以发现这个方程对这道题成立的条件正是 \(a_i\le p_i\),或者说是 \(a_i<p_i\),因为初始血量 \(a_i\) 是不能凭空减少的,所以要求 \(a_i<p_i\),在这道题里面 \(a_i=p_i\) 的情况还要特判(但是数据太水不特判也能过)。

    对于方程组 \(A_iX=a_i\pmod{p_i}\) 我们能很快想到扩展中国剩余定理,但是随即又想到它只能处理 \(X\) 前面没有系数的情况,那可怎么办呢?显然不能直接把 \(A_i\) 除到右边去,因为 \(A_i\)\(\mod p_i\) 下未必有逆元。

    把这个式子写成一般形式:\(p_it-A_iX=\gcd(p_i,A_i)\),用扩欧求出特解 \(t',X'\) 之后,我们就可以得到 \(X\) 的通解了:\(X=X'+k\times \frac{p_i}{\gcd(p_i,A_i)}\)

    原式子的通解 \(X=X'\times \frac{a_i}{\gcd(p_i,A_i)}+k\times \frac{p_i}{\gcd(p_i,A_i)}\)

    换成同余方程就是 \(X=X'\times \frac{a_i}{\gcd(p_i,A_i)}\pmod {\frac{p_i}{\gcd(p_i,A_i)}}\)

    然后用扩展中国剩余定理合并即可。

    代码

    //12252024832524
    #include <bits/stdc++.h>
    #define TT template<typename T>
    using namespace std; 
    
    typedef long long LL;
    const int MAXN = 100005;
    int n,m;
    LL a[MAXN],p[MAXN],aw[MAXN],A[MAXN],r[MAXN];
    multiset<LL> s;
    
    LL Read()
    {
    	LL x = 0,f = 1;char c = getchar();
    	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
    	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
    	return x * f;
    }
    TT void Put1(T x)
    {
    	if(x > 9) Put1(x/10);
    	putchar(x%10^48);
    }
    TT void Put(T x,char c = -1)
    {
    	if(x < 0) putchar('-'),x = -x;
    	Put1(x); if(c >= 0) putchar(c);
    }
    TT T Max(T x,T y){return x > y ? x : y;}
    TT T Min(T x,T y){return x < y ? x : y;}
    TT T Abs(T x){return x < 0 ? -x : x;}
    
    LL gsc(const LL x,const LL y,const LL MOD)
    {
    	LL ret = x*y - (LL)((long double)x/MOD*y+0.5)*MOD;
    	return (ret%MOD+MOD)%MOD;
    } 
    LL exgcd(LL a,LL b,LL &x,LL &y)
    {
    	if(!b) {x = 1;y = 0;return a;}
    	LL ret = exgcd(b,a%b,y,x);
    	y -= a/b*x; return ret;
    }
    
    int main()
    {
    //	freopen("dragon.in","r",stdin);
    //	freopen("dragon.out","w",stdout);
    	for(int T = Read(); T ;-- T)
    	{
    		bool sp = 1; s.clear();
    		n = Read(); m = Read();
    		for(int i = 1;i <= n;++ i) a[i] = Read();
    		for(int i = 1;i <= n;++ i) p[i] = Read(),sp &= p[i] == 1;
    		for(int i = 1;i <= n;++ i) aw[i] = Read();
    		for(int i = 1;i <= m;++ i) s.insert(Read());
    		for(int i = 1;i <= n;++ i)
    		{
    			auto it = s.upper_bound(a[i]);
    			if(it != s.begin()) --it;
    			A[i] = *it; s.erase(it);
    			s.insert(aw[i]);
    		}
    		if(sp)
    		{
    			LL ans = 0;
    			for(int i = 1;i <= n;++ i) ans = Max(ans,(a[i]+A[i]-1)/A[i]);
    			Put(ans,'\n');
    		}
    		else
    		{
    			bool gg = 0;//G!
    			for(int i = 1;i <= n;++ i)
    			{
    				LL x,y,d; d = exgcd(p[i],A[i],x,y); p[i] /= d; A[i] /= d;
    				if(a[i] % d) {gg = 1;break;} a[i] /= d;
    				r[i] = gsc(y,a[i],p[i]);
    			}
    			for(int i = 1;i < n && !gg;++ i)
    			{
    				if(r[i] > r[i+1]) swap(r[i],r[i+1]),swap(p[i],p[i+1]);
    				LL x,y,d,cha = r[i+1]-r[i]; d = exgcd(p[i],p[i+1],x,y);
    				if(cha % d) {gg = 1;break;}
    				//p1x-p2y=r2-r1
    				p[i+1] = p[i] / d * p[i+1]; x = gsc(x,cha/d,p[i+1]);
    				r[i+1] = (r[i] + gsc(x,p[i],p[i+1])) % p[i+1];
    			}
    			if(gg) {Put(-1,'\n');continue;}
    			Put(r[n]>0?r[n] : p[n],'\n');
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    EyeWitness
    中间件解析漏洞
    反思
    【转载】python的logging模块
    RobotFramework中使用Exit For Loop If退出For循环
    python使用ssl的单向认证和双向认证的客户端代码
    使用iptables监测端口流量
    打开GUI面板通过可视化的形式来创建Vue项目
    C#程序设计: 猫大叫一声,所有的老鼠都开始逃跑,主人被惊醒。
    递归算法
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/15851074.html
Copyright © 2020-2023  润新知