校内训练0602 习题exercise

【题目大意】

f(i)=((Af(i-1)+B)/(Cf(i-1)+D)) mod P。

给出f(0), A, B, C, D, P, n,求f(n)。

多组数据T<=1e4

n<=1e18, P <= 1e9, |f(0)|,|A|,|B|,|C|,|D| <= 1e9

保证任何时候存在逆元。

【题解】

首先我们有一种O(TP)的做法:找循环节。

考场上因为数据原因是可以AC的。。

# include <map>
# include <stdio.h>
# include <assert.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 5e5 + 10;

# define RG register
# define ST static

int A, B, C, D, mod, lm, rm;
ll f[2000010], n;
map<int, int> mp;

inline ll exgcd(ll a, ll b, ll &x, ll &y) {
    if(b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    exgcd(b, a%b, x, y);
    ll t = x;
    x = y;
    y = t - (a/b)*y;
}

inline ll getinv(ll n) {
    ll x, y;
    exgcd(n, (ll)mod, x, y);
    x = (x%mod + mod) % mod;
    return x;
}

inline void sol() {
    scanf("%lld%d%d%d%d%lld%d", &f[0], &A, &B, &C, &D, &n, &mod);
    A = (A+mod)%mod; B = (B+mod)%mod;
    C = (C+mod)%mod; D = (D+mod)%mod;
    mp.clear(); lm = rm = -1; mp[f[0]] = 0;
    for (int i=1; i<=mod; ++i) {
        f[i] = (A*f[i-1] + B) % mod * getinv(C*f[i-1] + D) % mod;
        if(mp.find(f[i]) != mp.end()) {
            lm = mp[f[i]], rm = i;
            break;
        }
        mp[f[i]] = i;
    }
//    printf("%d %d\n", lm, rm);
    assert(lm != -1 && rm != -1);
    if(n <= lm) printf("%lld\n", f[n]);
    else printf("%lld\n", f[(n-lm)%(rm-lm)+lm]);
}

int main() {
    freopen("exercise.in", "r", stdin);
    freopen("exercise.out", "w", stdout);
    int T; cin >> T;
    while(T--) sol();
    return 0;
}

标准做法是

f(i)=((Af(i-1)+B)/(Cf(i-1)+D))

f(i-1)=((Af(i-2)+B)/(Cf(i-2)+D))

那么

f(i)=((A^2+BC)f(i-2)+(AB+BD))//((AC+CD)f(i-2)+(CD+D^2))

相当于两个2*2的矩阵乘在一起。

那么矩乘即可。

# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 5e5 + 10;

# define RG register
# define ST static

int f0, A, B, C, D, mod, ans;
ll n;

inline ll exgcd(ll a, ll b, ll &x, ll &y) {
    if(b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    exgcd(b, a%b, x, y);
    ll t = x;
    x = y;
    y = t - (a/b)*y;
}

inline int getinv(ll n) {
    ll x, y;
    exgcd(n, (ll)mod, x, y);
    x = (x%mod + mod) % mod;
    return x;
}

struct matrix {
    int a[3][3], n;
    inline void set() {memset(a, 0, sizeof a);}
    friend matrix operator * (matrix a, matrix b) {
        matrix c; c.set();
        for (int i=1; i<=2; ++i)
            for (int j=1; j<=2; ++j)
                for (int k=1; k<=2; ++k)
                    (c.a[i][j] += 1ll * a.a[i][k] * b.a[k][j] % mod) %= mod;
        return c;
    }
    friend matrix operator ^ (matrix a, ll b) {
        matrix c; c.set(); c.a[1][1] = c.a[2][2] = 1;
        while(b) {
            if(b&1) c=c*a;
            a=a*a;
            b >>= 1;
        }
        return c;
    }
}E;

inline void sol() {
    scanf("%d%d%d%d%d%lld%d", &f0, &A, &B, &C, &D, &n, &mod);
    A = (A+mod) % mod; B = (B+mod) % mod; C = (C+mod) % mod; D = (D+mod) % mod;
    E.set(); E.a[1][1] = A, E.a[1][2] = B, E.a[2][1] = C, E.a[2][2] = D;
    E = E^n;
    A = E.a[1][1], B = E.a[1][2], C = E.a[2][1], D = E.a[2][2];
    ans = getinv((ll)C * f0 + D);
    ans = 1ll * ans * (1ll * A * f0 % mod + B) % mod;
    printf("%d\n", ans);
}

int main() {
    freopen("exercise.in", "r", stdin);
    freopen("exercise.out", "w", stdout);
    int T; cin >> T;
    while(T--) sol();
    return 0;
}

时间: 2024-10-04 00:04:30

校内训练0602 习题exercise的相关文章

校内训练0602 阿狸的统计学count

[题目大意] 一个数列a[]有n个数,m次操作: 1 l r x:将a[l...r]都改成x 2 l r:求a[l...r]中数在当前区间出现率>=p%的数,为了方便做题,你可以输出k个数,满足k*p<=100,如果k个数中完全包含了答案,那么就判为正确. 1<=n,m,a[i],x<=150000, 20<=p<=100 [题解] 考虑之前做过的一个题:有一个数在区间中出现了>50%,求这个数:做法是我随便找出2个不同的数消去,到不能消的时候,最后剩下的那个数就

「csp校内训练 2019-10-24」解题报告

「csp校内训练 2019-10-24」解题报告 T1.猴猴吃苹果 \(Description\) 猴猴最喜欢在树上玩耍,一天猴猴又跳上了一棵树,这棵树有 \(N \ (N \leq 50000)\) 个苹果,每个苹果有一个编号,分别为 \(0\) ~ \(N - 1\) 它们之间由 \(N-1\) 个树枝相连,猴猴可以从树枝的一端爬到树枝的另一端,所以猴猴可以从任意一个苹果的位置出发爬到任意猴猴想去的苹果的位置. 猴猴开始在编号为 \(K \ (K < N)\) 的苹果的位置,并且把这个苹果吃

「csp校内训练 2019-10-30」解题报告

「csp校内训练 2019-10-30」解题报告 T1.树 题目链接(逃) \(Description\): 现在有一棵树,共 \(N\) 个节点. 规定:根节点为 \(1\) 号节点,且每个节点有一个点权. 现在,有 \(M\) 个操作需要在树上完成,每次操作为下列三种之一: \(1 \ x \ a\):操作 \(1\),将节点 \(x\) 点权增加 \(a\). \(2 \ x \ a\):操作 \(2\),将以节点 \(x\) 为根的子树中所有点的权值增加 \(a\). \(3 \ x\)

2017-4-7校内训练

丧病hzwer的ctsc训练赛 My AC:3/4 A.[Ctsc2014]企鹅QQ 思路:乱hash,我比较菜,写的丑代码各种WA+TLE,好久才A掉. #include<cstdio> #include<algorithm> using namespace std; #define ll long long #define MN 200 #define MX 6000000 #define MM 9000001 #define MOD1 890123798112473LL st

20170910校内训练

CCT 最近学校又发了n本五三题霸,BBS看到后十分高兴.但是,当他把五三拿到手后才发现,他已经刷过这些书了!他又认真地看了一会儿,发现新发的这些五三是2017版的,而他刷的是2016版的.现在他想找出所有他没有刷过的题来刷.每本五三都有m道题,并且它的特征(即它和去年版本的五三的差距)可以用一个m位二进制数来代表,二进制位上的1代表该题不同,0代表该题相同.比如4(100)就代表题目3和去年的有不同.5(101)就代表题目1和题目3和去年的有不同.而BBS热衷于给自己找麻烦,他要选择连续一段的

2017-3-3校内训练

hzwer出丧题虐人啦 ACM赛制 4/7 A.恼人的青蛙 题目大意:给定N*M矩阵上K个点,定义一条合法路径为从矩形外一点沿一条直线穿过矩形,每次走相同长度且在矩形内每步都要踩在给定点上,问经过给定点最多的路径经过几个点(若小于3输出0)(N,M,K<=5000). 思路:把点按横坐标第一关键字纵坐标第二关键字排序,f[i][j]表示有一条到i的路径,i上一个点是j,此时路径经过点数,每次确定i,j后就可以根据i,j算出j再前一个点的坐标,直接转移,复杂度O(K^2).评测机极慢稍微卡卡常才能

【三中校内训练】旅行

[题解] 显然的这是一道树形DP的题目 这里令f[i][0]为从i出发向以它为根的子树里走直到不能走的最大.最小价值 (不能走是什么自己阅读题目) 令s为x的儿子,w[i][j]为i和j之间的边的长度,则 f[x][0]=max(f[s][1]+w[s][i]) f[x][1]=min(f[s][0]+w[s][i]) 显然的通过这种方法,我们可以得到60分 可是,如何优化到线性呢 我们考虑一个节点x,x向某条边走的情况出现了很多次,浪费了很多时间 我们定义h[x][0/1]为从x出发,经过x的

校内训练0609 problem c

[题目大意] 给一棵树,求有多少条路径满足总和-最大值 是P的倍数 n<=10^5, P<=10^7 [题解] 一看就是点分治嘛 不考虑子树合并,考虑poj1741的做法,每次考虑经过重心的路径,用优先队列,从小到达添加并求答案即可. 容斥下. # include <queue> # include <stdio.h> # include <string.h> # include <iostream> # include <algorith

[3.10校内训练赛]

真的报警啦,hzwer又出一堆丧题虐人啦..... ------------------------------------------- A.[poj-1190]生日蛋糕 要做一个m层的蛋糕,每一层有高度和半径,且要分别比它上面的那一层的高度和半径大至少一,给定总体积n,求最小的侧面和顶上的面积之和m<=20,n<=10000 搜索....但是要加上比较强的剪枝. 1.如果此时的半径和高度无法建出剩余体积那么大的蛋糕,剪掉.这种情况我们不考虑半径和高度的减小,直接用((r-1)^2+(h-1