2019 ICPC 南昌网络赛 H. The Nth Item

2019 ICPC 南昌网络赛 H. The Nth Item


题目大意:已知一个数列F(n):
F(0)=0,F(1)=1
F(n)=3∗F(n−1)+2∗F(n−2),(n≥2)

给你一个操作次数Q,再给你一个初始n的值,令A1=F(n1),A2=F(n2),…Aq=F(nq),其中n1=n,ni=Ai-1*Ai-1^ni-1,输出所有A的异或和。

解法:偷鸡成功!不知道多少人是按题解那样预处理来降低复杂度的,估计大多数都不是正解做法吧。
首先F(n)是类斐波那契数列,第一反应矩阵快速幂,一看询问107,要O(1)!计划破产。仔细读题发现是异或,一定要在线操作,但是怎么在常数时间内直接知道答案呢?我们尝试去找F(n)的循环节,再次失败,模数太大找不到,倒是把F(n)的公式推了出来。带根号17,无法快速幂,队友找到该模数下根号17的代替数,转换,把每次查询复杂度降到了log,只要几次快速幂就可以,没了矩阵的常数。因为过的人很多,就以为数据很水,降到log就可以了,于是尝试交了一发。
你以为AC了?TLE!!!果然再多努力都是白费。
本来想着放弃,队友没事干打了个表,循环了!马上换了几个n多打了几个表,惊奇的发现,在Q达到105以后,不知道为什么,答案会出现循环,把Q分
一下奇数偶数就可以,一发AC。

下面是AC代码:

#include <bits/stdc++.h>
using namespace std;
using namespace chrono;
const int N = 100000005;
const int M = 998244353;
const int S = 473844410;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1);
const double eps = 1e-8;
#define ms(x, y) memset((x), (y), sizeof(x))
#define mc(x, y) memcpy((x), (y), sizeof(y))
typedef long long ll;
typedef unsigned long long ull;
#define fi first
#define se second
#define mp make_pair
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
#define bg begin
#define ed end
#define pb push_back
#define al(x) (x).bg(), (x).ed()
#define st(x) sort(al(x))
#define un(x) (x).erase(unique(al(x)), (x).ed())
#define fd(x, y) (lower_bound(al(x), (y)) - (x).bg() + 1)
#define ls(x) ((x) << 1)
#define rs(x) (ls(x) | 1)
template <class T>
bool read(T & x) {
    
    
    char c;
    while (!isdigit(c = getchar()) && c != '-' && c != EOF);
    if (c == EOF) return false;
    T flag = 1;
    if (c == '-') {
    
     flag = -1; x = 0; } else x = c - '0';
    while (isdigit(c = getchar())) x = x * 10 + c - '0';
    x *= flag;
    return true;
}
template <class T, class ...R>
bool read(T & a, R & ...b) {
    
    
    if (!read(a)) return false;
    return read(b...);
}
mt19937 gen(steady_clock::now().time_since_epoch().count());
#define LL ll
LL a_b_MOD_c(LL a,LL b,LL mod){
    
    
    assert(b >= 0);
	LL ret = 1;
	a %= mod;
	while(b){
    
    
		if(b & 1) ret = ret * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return ret;
}
const int inv2 = a_b_MOD_c(2, M - 2, M);
const int invS = a_b_MOD_c(S, M - 2, M);
const int a = S + 3;
const int b = 3 - S + M;
//(x^2)%n=a 求平方剩余,n必须是奇素数
//注意:如果a为负,则看题意,是否要化为a=(a%n+n)%n
int modsqr(int a,int n){
    
    
	int b,k,i,x;
	if(n==2) return a%n;
	if(a_b_MOD_c(a,(n-1)/2,n)==1){
    
    
		if(n%4==3)
			x=a_b_MOD_c(a,(n+1)/4,n);
		else{
    
    
			for(b=1;a_b_MOD_c(b,(n-1)/2,n)==1;b++){
    
    
				i=(n-1)/2;
				k=0;
			}
			do{
    
    
				i/=2;
				k/=2;
				if((a_b_MOD_c(a,i,n)*a_b_MOD_c(b,k,n)+1)%n==0)
					k+=(n-1)/2;
			}
			while(i%2==0);
			x=(a_b_MOD_c(a,(i+1)/2,n)*a_b_MOD_c(b,k/2,n))%n;
		}
		if(x*2>n)
			x=n-x;
		return x;
	}
	return -1;
}
const int step = 100000;
int main()
{
    
    
    time_point<steady_clock> start = steady_clock::now();

    int Q;
    ll n, ans = 0, plast, t = 0;
    read(Q, n);
    for (int i = 1; i <= Q; i++) {
    
    
        ll last = n <= 1 ? n : (a_b_MOD_c(a, n, M) - a_b_MOD_c(b, n, M) + M) * invS % M * a_b_MOD_c(inv2, n, M) % M;
        ans ^= last;
        n ^= last * last;
        
        if (i > 1) {
    
    
            if (last == plast) {
    
    
                t = i;
                plast = last;
                break;
            }
        }
        plast = last;
    }
    // cout << "check 1: " << t << ' ' << plast << endl;
    if (t && (Q - t) % 2 == 1)
        ans ^= plast;
    // cout << "check 2: " << t << ' ' << plast << endl;
    printf("%lld\n", ans);

    cerr << endl << "------------------------------" << endl << "Time: "
         << duration<double, milli>(steady_clock::now() - start).count()
         << " ms." << endl;

    return 0;
}

猜你喜欢

转载自blog.csdn.net/yzsjwd/article/details/100636558
今日推荐