2.4 【高精度】 FJOI2007 轮状病毒

本文介绍了FJOI2007轮状病毒问题的解题思路,通过观察规律发现了一个类斐波那契数列,并使用高精度计算实现了递推求解。适用于对算法竞赛和数列问题感兴趣的读者。

FJOI2007 轮状病毒

传送门:https://www.luogu.org/problemnew/show/P2144

暴力找规律
发现n=1~5时答案是1,5,16,45,121
奇数项是平方数,偶数项是平方数减4
1,5,16,45,121 分别是1^2,3^2-4,4^2,7^2-4,11^2
1,3,4,7,11这个数列有类似于斐波那契数列的性质,只不过前两项是1和3罢了
那么我们就可以递推求这个类斐波那契数列的第n项,然后平方,然后再根据n的奇偶来决定是否减4
高精度代码如下

#include<cstdio> 
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<iostream>
#include<cstdlib>
using namespace std;
class Bigint{
    public:
    int size,num[10000];
    Bigint(){
        size=0;
        memset(num,0,sizeof(num));
    }
    Bigint(int data)
    {
        size=0;
        while(data!=0)
        {
            size++;
            num[size]=data%10;
            data/=10;
        }
    }
    void init(int data)
    {
        size=0;
        while(data!=0)
        {
            size++;
            num[size]=data%10;
            data/=10;
        }
    }
};
Bigint operator + (Bigint A,Bigint B){
    Bigint ans;
    int s=max(A.size,B.size);
    ans.size=s;
    for(int i=1;i<=s;i++)
        ans.num[i]=A.num[i]+B.num[i];
    for(int i=1;i<=s;i++)
        if(ans.num[i]>=10)
        {
            ans.num[i+1]+=ans.num[i]/10;
            ans.num[i]%=10;
        }
    if(ans.num[s+1]!=0)
        ans.size++;
    return ans;
}
Bigint operator - (Bigint A,Bigint B){
    Bigint ans;
    int s=max(A.size,B.size);
    ans.size=s;
    for(int i=1;i<=s;i++)
        ans.num[i]=A.num[i]-B.num[i];
    for(int i=1;i<=s;i++)
        if(ans.num[i]<0)
        {
            ans.num[i+1]--;
            ans.num[i]=(ans.num[i]+10)%10;
        }
    while(ans.num[ans.size]==0)
        ans.size--;
    return ans;
}
Bigint operator * (Bigint A,Bigint B){
    Bigint ans;
    int s1=A.size,s2=B.size;
    for(int i=1;i<=s1;i++)
        for(int j=1;j<=s2;j++)
            ans.num[i+j-1]+=A.num[i]*B.num[j];
    int s=s1+s2-1;
    int k=1;
    while(ans.num[k]!=0||k<=s)
    {
        ans.num[k+1]+=ans.num[k]/10;
        ans.num[k]%=10;
        k++;
    }
    if(ans.num[k]==0)k--;
    ans.size=k;
    return ans;
}
ostream & operator << (ostream &os,Bigint A){
    int s=A.size;
    for(int i=s;i>=1;i--)
        os<<A.num[i];
    return os;
}
Bigint P,Q,ANS;
int n;
int main(){
    cin>>n;
    P.init(1);
    Q.init(3);
    for(int i=3;i<=n;i++)
    {
        if(i%2)P=P+Q;
        else Q=P+Q;
    }
    if(n%2)ANS=P;
    else ANS=Q;
    ANS=ANS*ANS;
    if(n%2==0)ANS=ANS-4;
    cout<<ANS<<endl;
    return 0;
}


LLAP.

### 关于洛谷平台上线段树练习题目的推荐 #### 题目一:P3810 【模板】线段树 1 此题目作为入门级的线段树构建与基本操作实现,适合初学者掌握线段树的基础概念和简单应用。通过这道题可以熟悉如何在线段树上执行单点更新以及区间求和的操作[^2]。 ```cpp #include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 5; struct SegmentTree { int sum[maxn << 2]; void pushUp(int rt) {sum[rt] = sum[rt<<1] + sum[rt<<1|1];} void build(int l, int r, int rt){ if(l == r){ scanf("%d", &sum[rt]); return ; } int m = (l+r)>>1; build(lson); build(rson); pushUp(rt); } // Other functions like update and query can be implemented here. }; int main(){ SegmentTree tree; int n,m,opt,x,y,k; char str[2]; while(scanf("%d%d",&n,&m)!=EOF){ memset(tree.sum,0,sizeof(tree.sum)); tree.build(1,n,1); for(int i=0;i<m;++i){ getchar(); gets(str); sscanf(str,"%d %d %d",&opt,&x,&y); switch(opt){ case 1 : k=y-tree.a[x]; tree.update(x,k,1,n,1);break; case 2 : printf("%lld\n",tree.query(x,y,1,n,1)); break; } } } return 0; } ``` #### 题目二:P2791 幼儿园篮球题 该问题不仅考察了对线段树的理解程度,还涉及到更复杂的逻辑思考能力。在这个场景下,需要利用线段树来高效解决有关子树内节点权重总和的问题,在实际编程竞赛中具有较高的实用性价值[^1]。 #### 题目三:P4566 [FJOI2018]新型城市化 这是一个较为高级的应用实例,涉及动态开点线段树的知识点。对于想要深入研究数据结构优化技巧的学习者来说是一个很好的挑战对象。这类题目有助于提高解决问题的能力,并加深对复杂算法设计模式的认识。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值