zoukankan      html  css  js  c++  java
  • Luogu P4774 屠龙勇士

    题目太长了懒得概括

    题解

    multiset 预处理出第 (i) 条龙对应的剑攻击力 (s_i) ,可以得到同余方程 (x_i s_i equiv a_i pmod {p_i})
    用扩欧求到一个解 (x_i) 后,可以得到 (x = x_i + k dfrac{p_i}{gcd(p_i,s_i)}) 也就是 (x equiv x_i pmod {dfrac{p_i}{gcd(p_i,s_i)} })
    (n) 条新的同余方程进行 exCRT 即可。
    注意,数据中若不满足特性1,则 (p_i=1) , 所以 (x = maxlimits_{1 leq i leq n} left{ leftlceil dfrac{a_i}{s_i} ight ceil ight})

    好像还有其他做法,设前 (i - 1) 个方程的答案为 (ans) , 模数为 (m) ,则前 (i) 个方程的答案应为 (ans gets ans + mx_i)
    得到 (s_i(ans + mx_i) = a_i pmod {p_i})((s_im)x_i = a_i - s_ianspmod {p_i}) 。同样用扩欧即可。

    坑点挺多的。。。
    注意模数!!!*
    会爆 long long ,所以要用慢速乘。

    #include <cstdio>
    #include <cctype>
    #include <set>
    
    using std::multiset;
    using std::max;
    
    #define MAX_N (100000 + 5)
    #define MAX_M (100000 + 5)
    
    typedef long long LL;
    int T;
    int n, m;
    LL a[MAX_N], p[MAX_N];
    int b[MAX_N];
    multiset<LL> S;
    int s[MAX_N];
    LL g;
    
    int Read_Int()
    {
    	int res = 0;
    	char ch = getchar();
    	while (!isdigit(ch)) ch = getchar();
    	while (isdigit(ch)) res = res * 10 + ch - '0', ch = getchar();
    	return res; 
    }
    
    LL Read_LL()
    {
    	LL res = 0;
    	char ch = getchar();
    	while (!isdigit(ch)) ch = getchar();
    	while (isdigit(ch)) res = res * 10 + ch - '0', ch = getchar();
    	return res; 
    }
    
    LL Mul(LL x, LL y, LL mod)
    {
    	LL res = 0;
    	while (y)
    	{
    		if (y & 1) res = (res + x) % mod;
    		x = (x + x) % mod;
    		y >>= 1;
    	}
    	return res;
    }
    
    void exGCD(LL a, LL b, LL & x, LL & y)
    {
    	if (!b)
    	{
    		g = a;
    		x = 1;
    		y = 0;
    		return;
    	}
    	exGCD(b, a % b, y, x);
    	y -= a / b * x;
    }
    
    LL exCRT()
    {
    	LL ans;
    	if (p[1] < a[1])
    	{
    		ans = 0;
    		for (int i = 1; i <= n; ++i)
    		{
    			ans = max(ans, (a[i] - 1) / s[i] + 1);
    		}
    		return ans;
    	}
    	LL m, x, y, tmp, last;
    	exGCD(s[1], p[1], x, y);
    	if (a[1] % g) return -1;
    	m = p[1] / g;
    	x = (x % p[1] + p[1]) % p[1];
    	ans = Mul(x, a[1] / g, p[1]);
    	for (int i = 2; i <= n; ++i)
    	{
    		exGCD(s[i], p[i], x, y);
    		if (a[i] % g) return -1;
    		x = (x % p[i] + p[i]) % p[i];
    		last = Mul(x, a[i] / g, p[i]);
    		p[i] /= g;
    		exGCD(m, p[i], x, y);
    		if ((last - ans) % g) return -1;
    		tmp = p[i] / g;
    		x = (x % tmp + tmp) % tmp;
    		x = Mul(x, ((last - ans) / g % tmp + tmp) % tmp, tmp);
    		ans += x * m;
    		m = m / g * p[i];
    		ans %= m;
    	}
    	return ans % m; // 记得mod!!! 
    }
    
    int main()
    {
    	T = Read_Int();
    	multiset<LL>::iterator it;
    	while (T--)
    	{
    		n = Read_Int();
    		m = Read_Int();
    		for (int i = 1; i <= n; ++i) a[i] = Read_LL();
    		for (int i = 1; i <= n; ++i) p[i] = Read_LL();
    		for (int i = 1; i <= n; ++i) b[i] = Read_Int();
    		for (int i = 1; i <= m; ++i) S.insert(Read_Int());
    		for (int i = 1; i <= n; ++i)
    		{
    			it = S.upper_bound(a[i]);
    			if (it != S.begin()) --it;
    			s[i] = *it;
    			S.erase(it);
    			S.insert(b[i]);
    		}
    		S.clear();
    		printf("%lld
    ", exCRT());
    	}
    	return 0;
    }
    
  • 相关阅读:
    SQL SERVER批量/单个修改表的所有者
    设置电脑右下角显示自己的大名
    javascript 事件查询 综合
    电脑命令大全值得珍藏
    仿flash超炫焦点图播放器 · javascript for jquery
    VirtualBox使用本地硬盘分区的权限问题
    同步时间并更新到计算机
    linux下电子词典里的扩展存储卡不能访问到的问题
    virtualbox 3.0.4终于可以共享剪贴板了
    批量更改mp3文件ID3编码的脚本
  • 原文地址:https://www.cnblogs.com/kcn999/p/13515671.html
Copyright © 2011-2022 走看看