牛客多校第九场部分题题解

中国剩余定理-循环节

  • 题目:The power of Fibonacci

  • 链接:https://ac.nowcoder.com/acm/contest/889/A

  • 大意:给定n<=1e9,m<=1e3求 ( ∑ i = 0 n F i m ) m o d 1 e 9 (\sum_{i=0}^nF_i^m)mod 1e9 (i=0nFim)mod1e9

  • 分析:有一个要注意的地方就是取模用的是1e9而不是某个大质数,这是有特殊的用意的。因为根据中国剩余定理,我们可以通过 ( ∑ i = 0 n F i m ) m o d ( 2 9 ) (\sum_{i=0}^nF_i^m)mod (2^9) (i=0nFim)mod(29) ( ∑ i = 0 n F i m ) m o d ( 5 9 ) (\sum_{i=0}^nF_i^m)mod (5^9) (i=0nFim)mod(59)来求 ( ∑ i = 0 n F i m ) m o d 1 e 9 (\sum_{i=0}^nF_i^m)mod 1e9 (i=0nFim)mod1e9 2 9 = 512 , 5 9 = 1953125 2^9=512,5^9=1953125 29=512,59=1953125这样任务就变简单了。另外由于是模空间,所以肯定是有循环节的,根据结论/经验/盲猜,循环节应该是mod周围,比mod不会大多少。于是可以提前算出循环节,再根据循环节快速算出 ( ∑ i = 0 n F i m ) m o d ( 2 9 ) (\sum_{i=0}^nF_i^m)mod (2^9) (i=0nFim)mod(29) ( ∑ i = 0 n F i m ) m o d ( 5 9 ) (\sum_{i=0}^nF_i^m)mod (5^9) (i=0nFim)mod(59)。然后就可以求ans了

#include
using namespace std;
typedef long long ll;
ll n, m;
int f[50000000];
int qpow(ll a, int b, int p)
{
	a %= p; ll ret = 1;
	while (b)
	{
		if (b & 1)ret = ret * a%p;
		b >>= 1; a = a * a%p;
	}
	return ret;
}
ll inv(ll a, ll p) { return qpow(a, p - 1, p); }
ll findr(int p)
{
	ll ans(0);
	f[0] = 0; f[1] = 1;
	int i=1;
	do
	{
		++i;
		f[i] = f[i - 1] + f[i - 2];
		if (f[i] >= p)f[i] -= p;
	} while ((f[i - 1] != 0 )||( f[i] != 1));
	int len = (i - 2) - 0 + 1;
	for (int i = 0; i < len; ++i)
	{
		ll cnt = n / len; if (i <= (n%len))++cnt;
		ans = (1ll * qpow(f[i], m, p)*cnt+ans) %p;
	}
	return ans;
}
int main()
{
	cin >> n >> m;
	ll ans2 = findr(512);
	ll ans5 = findr(1953125);
	ll M = 1e9;
	ll m2 = 512, m5 = 1953125;
	ll M2 = 1953125, M5 = 512;
	//ll t2 = inv(M2, 512), t5 = inv(M5, 1953125);
	ll t2 = 0;
	while ((t2 * M2 % m2) != 1)
		++t2;
	ll t5 = 0; 
	while ((t5 * M5 % m5 )!= 1)
		++t5;

	ll ans = (ans2*t2%M*M2%M + ans5 * t5%M*M5%M) % M;
	cout << ans << endl;
}

二次剩余

  • 题目:Quadratic equation

  • 链接:https://ac.nowcoder.com/acm/contest/889/B

  • 大意: ( x + y ) m o d p = b , ( x × y )   m o d   p = c (x+y)modp=b ,(x \times y) \bmod p = c (x+y)modp=b,(x×y)modp=c,输入x,y

  • 分析:简单解一下方程,然后就是二次剩余的板子了。主要是不懂二次剩余

#include
#define F(i,a,b) for(int i=(a);i<=int(b);++i)
using namespace std;
typedef long long ll;
#define MODED(n) ((n)<0?(n)%mod+mod:(n)%mod)
const int inf = 0x3f3f3f3f;
const int maxn = int(20);
const int mod = 1e9 + 7;
mt19937_64 gen(time(0));

struct T { ll x, y; };ll w;
//复数乘法
T mul_two(T a, T b, ll p)
{
	T ans;
	ans.x = (a.x*b.x%p + a.y*b.y%p*w%p) % p;
	ans.y = (a.x*b.y%p + a.y*b.x%p) % p;
	return ans;
}
//复数快速幂
T qpow_two(T a, ll n, ll p)
{
	T ans = { 1,0 };
	while (n)
	{
		if (n & 1) ans = mul_two(ans, a, p);
		n >>= 1; a = mul_two(a, a, p);
	}
	return ans;
}

ll qpow(ll a, ll n, ll p)
{
	ll ans = 1; a %= p;
	while (n)
	{
		if (n & 1) ans = ans * a%p;
		n >>= 1; a = a * a%p;
	}
	return ans % p;
}
//勒让德符号
ll Legendre(ll a, ll p) { return qpow(a, (p - 1) >> 1, p); }

//求x^2=b mod p  的解
int solve(ll b, ll p) {
	if (b == 0) return 0;
	if (b == 1) return 1;
	if (Legendre(b, p) + 1 == p) return -1;
	ll a;
	while (1)
	{
		a = gen() % p;
		ll t = a * a - b;
		w = (t%p + p) % p;
		if (Legendre(w, p) + 1 == p) break;
	}
	T tmp = { a,1 };
	T ans = qpow_two(tmp, (p + 1) >> 1, p);
	return ans.x;
}
#define endl '\n'
int main()
{
#ifndef endl
	freopen("C:\\Users\\VULCAN\\Desktop\\data.in", "r", stdin);
	cout << "************************************Local Test*********************************" << endl;
#endif // !endl
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int ca;cin>>ca;
	while(ca--)
	{
		ll b, c; cin >> b >> c;
		ll delta = MODED(b*b - 4*c);
		ll gdel = solve(delta, mod);
//		cout<
		if (gdel == -1)
			cout << "-1 -1" << endl;
		else
		{
			ll inv2 = (mod + 1) / 2;
			ll x = (b + gdel)*inv2%mod;
			ll y = MODED(b - gdel)*inv2%mod;
			x = MODED(x); y = MODED(y); if (x > y)swap(x, y);
			cout << x << ' ' << y << endl;
		}
	} 


	return 0;
}
//What to Debug
/*
-1.最好把全部warning都X掉,否则:https://vjudge.net/solution/19887176
0.看看自己是否有可能需要快读,禁endl
1.数组越界,爆int,浮点精度(查看精度是否达到题目要求,看有没有浮点数比较:eps),取模操作,初始化数组,边缘数据,输出格式(cas),强制在线是否更新了las
2.通读代码,代码无逻辑错误
3.读题,找到题意理解失误或算法错误
4.放弃
*/

你可能感兴趣的:(ACM)