zoukankan      html  css  js  c++  java
  • 洛谷 P3868 [TJOI2009]猜数字

    洛谷 P3868 [TJOI2009]猜数字

    思路

    中国剩余定理 + 快速乘

    题目要求找到最小的(nin N),满足对于(forall iin [1,k]),有(b_i | (n-a_i))

    我们试着来转化一下这个式子

    (b_i|(n-a_i)),也就是说((n-a_i))在模(b_i)意义下同余(0),即(n - a_iequiv 0( ext{mod} b_i)),进一步转化,就能得到(nequiv a_i( ext{mod} b_i)),转化到多个式子就是

    [egin{equation} left{ egin{array}{lr} n equiv a_1 ( ext{mod} b_1)\ n equiv a_2 ( ext{mod} b_2)\……\ n equiv a_k ( ext{mod} b_k) end{array} ight. end{equation}]

    这个式子是不是很眼熟?没错,就是中国剩余定理的式子,因为题目中已经保证了(b_i)两两互素,所以我们就可以直接套中国剩余定理的板子了

    (N=prod_{i=1}^nb_i)(Mi=N/b_i)(x_i)是线性同余方程(M_ix_i≡1( ext{mod} b_i))的一个解(即(Mi)的逆元),最后的解即为(ans=sumlimits_{i=1}^ka_iM_ix_i)

    那么这样就完了嘛?

    此题终结其实不然

    这样交上去之后,会发现只有九十分,最后一个点(WA)了,因为这题要用快速乘,于是写上快速乘

    那么这样就完了嘛?

    此题终结其实也不然

    又交上去之后,发现还是九十分,不过这次错的点是第二个了。

    这是为什么呢?

    看题目条件:(∣a_i∣≤10^9)

    什么意思呢?意思就是(a_i)可能是负的!(出题人真是用心良苦

    处理的方法就是:快速乘传参时取模

    那么这样就完了嘛?

    兴冲冲的交上去,终于满分了,没错,这次真完了

    代码

    /*
    Author:loceaner
    中国剩余定理板子题 
    */
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define int long long
    using namespace std;
    
    const int A = 5e5 + 11;
    const int B = 1e6 + 11;
    const int mod = 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    
    inline int read() {
    	char c = getchar(); int x = 0, f = 1;
    	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
    	return x * f;
    }
    
    int n, N = 1, b[A], a[A], ans;
    
    inline int mul(int n, int m, int mod) {
    	int res = 0;
    	while (m) {
    		if (m & 1) res = (res + n) % mod;
    		n = (n + n) % mod, m >>= 1;
    	}
    	return res;
    }
    
    inline void exgcd(int a, int b, int &x, int &y) {
    	if (!b) x = 1, y = 0;
    	else exgcd(b, a % b, y, x), y -= a / b * x;
    }
    
    signed main() {
    	n = read();
    	for (int i = 1; i <= n; i++) a[i] = read();
    	for (int i = 1; i <= n; i++) b[i] = read(), N *= b[i];
    	for (int i = 1; i <= n; i++) {
    		int x, y, Mi = N / b[i];
    		exgcd(Mi, b[i], x, y);
    		ans = (ans + mul(mul(Mi, x % N + N, N), a[i] % N + N, N) % N + N) % N; 
    	}
    	cout << ans % N << '
    ';
    	return 0;
    }
    
  • 相关阅读:
    二分查找总结
    多线程之Timer和TimerTask
    多线程之线程间协作的两种方式:wait、notify、notifyAll和Condition
    java多线程之Callable、Future和FutureTask
    多线程之CountDownLatch、CyclicBarrier和Semaphore
    多线程之线程池的使用
    多线程之阻塞队列
    Transient关键字的使用
    多线程并发容器CopyOnWriteArrayList
    AtomicInteger学习
  • 原文地址:https://www.cnblogs.com/loceaner/p/12765133.html
Copyright © 2011-2022 走看看