[莫队算法 线段树 斐波那契 暴力] Codeforces 633H Fibonacci-ish II

题目大意:给出一个长度为n的数列a。

对于一个询问lj和rj。将a[lj]到a[rj]从小到大排序后并去重。设得到的新数列为b,长度为k,求F1*b1+F2*b2+F3*b3+...+Fk*bk。当中F为斐波那契数列。F1=F2=1。对每一个询问输出答案模m。

区间查询离线 用莫队算法

开棵权值线段树,然后用斐波那契的性质update

F(n+m)=F(n+1)*F(m)+F(n)*F(m-1);

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;

inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
	return *p1++;
}

inline void read(int &x)
{
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

int P;
int sx[30005];
int icnt;

inline int Bin(int x){
	return lower_bound(sx+1,sx+icnt+1,x)-sx;
}

struct SEGTREE{
	struct node{
		int k;
		int fk,fk_1;
		int a1,a2;
		friend node operator + (node &A,node &B){
			if (!A.k) return B;
			if (!B.k) return A;
			node ret;
			ret.k=A.k+B.k;
			(ret.fk=(A.fk+A.fk_1)*B.fk+A.fk*B.fk_1)%=P;
			(ret.fk_1=A.fk*B.fk+A.fk_1*B.fk_1)%=P;
			ret.a1=A.a1;
			(ret.a1+=A.fk*B.a2+A.fk_1*B.a1)%=P;
			ret.a2=A.a2;
			(ret.a2+=(A.fk+A.fk_1)*B.a2+A.fk*B.a1)%=P;
			return ret;
		}
	};
	node T[120005];
	int cnt[120005];
	int M,TH;
	inline void Build(int n){
		for (M=1,TH=0;M<n+2;M<<=1,TH++);
	}
	inline int Query(){
		return T[1].a1;
	}
	inline void Change(int s,int r){
		s+=M;
		if (r==1)
		{
			cnt[s]++;
			if (cnt[s]==1)
			{
				T[s].k=1;
				T[s].fk=1;
				T[s].fk_1=0;
				(T[s].a1=sx[s-M])%=P;
				(T[s].a2=sx[s-M])%=P;
				while (s>>=1)
					T[s]=T[s<<1]+T[s<<1|1];
			}
		}
		else if (r==-1)
		{
			cnt[s]--;
			if (cnt[s]==0)
			{
				T[s].k=0;
				T[s].fk=0;
				T[s].fk_1=0;
				T[s].a1=0;
				T[s].a2=0;
				while (s>>=1)
					T[s]=T[s<<1]+T[s<<1|1];
			}
		}
	}
}SEG;

int n,Q,B;
int a[30005],ans[30005];

struct event{
	int x,y,lpos;
	int idx;
	bool operator < (const event &B) const{
		return lpos==B.lpos?y<B.y:lpos<B.lpos;
	}
}eve[30005];

inline void Mos()
{
	int l=1,r=0;
	for (int i=1;i<=Q;i++)
	{
		while (r<eve[i].y) SEG.Change(Bin(a[++r]),1);
		while (r>eve[i].y) SEG.Change(Bin(a[r--]),-1);
		while (l<eve[i].x) SEG.Change(Bin(a[l++]),-1);
		while (l>eve[i].x) SEG.Change(Bin(a[--l]),1);
		ans[eve[i].idx]=SEG.Query();
	}
}

int main()
{
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	read(n); read(P); B=sqrt(n);
	for (int i=1;i<=n;i++)
		read(a[i]),sx[++icnt]=a[i];
	sort(sx+1,sx+icnt+1);
	icnt=unique(sx+1,sx+icnt+1)-sx-1;
	SEG.Build(icnt);
	read(Q);
	for (int i=1;i<=Q;i++)
	{
		read(eve[i].x); read(eve[i].y);
		eve[i].lpos=(eve[i].x-1)/B+1; eve[i].idx=i;
	}
	sort(eve+1,eve+Q+1);
	Mos();
	for (int i=1;i<=Q;i++)
		printf("%d\n",ans[i]);
	return 0;
}

然而出题人太奇妙,这样的做法常数极大,还是暴力短小精悍

#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e4+5;
pair<int,int> a[maxn];
int ans[maxn],step[maxn],f[maxn],l[maxn],r[maxn],last[maxn];

int main()
{
	freopen("t.in","r",stdin);
	freopen("t1.out","w",stdout);
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i].first),a[i].second=i;
    sort(a+1,a+1+n);
    f[0]=1,f[1]=1;
    for(int i=2;i<=n;i++)
        f[i]=(f[i-1]+f[i-2])%m;
    int q;scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        scanf("%d%d",&l[i],&r[i]);
        last[i]=-1;
    }
    for(int i=1;i<=n;i++)
    {
        int d = a[i].first % m;
        for(int j=1;j<=q;j++)
        {
            if(a[i].second<l[j]||a[i].second>r[j])continue;
            if(a[i].first==last[j])continue;
            ans[j]=(ans[j]+f[step[j]++]*d)%m;
            last[j]=a[i].first;
        }
    }
    for(int i=1;i<=q;i++)
        printf("%d\n",ans[i]);
}
时间: 2024-10-13 16:59:27

[莫队算法 线段树 斐波那契 暴力] Codeforces 633H Fibonacci-ish II的相关文章

【CF446C】DZY Loves Fibonacci Numbers (线段树 + 斐波那契数列)

Description ? 看题戳我 给你一个序列,要求支持区间加斐波那契数列和区间求和.\(~n \leq 3 \times 10 ^ 5, ~fib_1 = fib_2 = 1~\). Solution ? 先来考虑一段斐波那契数列如何快速求和,根据性质有 \[ \begin {align} fib_n &= fib_{n - 1} + fib_{n - 2} \ &= fib_ {n - 2} + fib_{n - 3} + fib_{n - 2} \ &= fib_{n -

HDU 4638 Group (莫队算法||线段树离散查询)

题目地址:HDU 4638 先写了一发莫队,莫队可以水过.很简单的莫队,不多说. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map> #include <set> #include <s

算法——动态规划篇——斐波那契数列

斐波那契数列,又称黄金分割数列,指的是这样一个数列:0.1.1.2.3.5.8.13.21.--在数学上,斐波纳契数列以如下被以递归的方法定义:F0=0,F1=1,Fn=F(n-1)+F(n-2)(n>=2,n∈N*)在现代物理.准晶体结构.化学等领域,斐波纳契数列都有直接的应用,为此,美国数学会从1960年代起出版了<斐波纳契数列>季刊,专门刊载这方面的研究成果. 以上内容来自百度百科.. 今天主要是想用动态规划的思想求解斐波那契数列,用来观察动态规划带来的优势,空间换时间,不重复求解

算法笔记_001:斐波那契数的多种解法

本篇文章解决的问题来源于算法设计与分析课程的课堂作业,主要是运用多种方法来计算斐波那契数.具体问题及解法如下: 一.问题1: 问题描述:利用迭代算法寻找不超过编程环境能够支持的最大整数的斐波那契数是第几个斐波那契数.(Java: 231-1 for int, 263-1 for long) 解决方案:针对问题1,此处要使用迭代法来解决,具体实现代码如下: //用迭代法寻找编程环境支持的最大整数(int型)的斐波那契数是第几个斐波那契数 public static int max_int_iter

ABAP算法题:斐波那契(Fibonacci)数列

斐波那契(Fibonacci)数列是经典的递推关系式定义的数列. 第一项是0,第二项是1,之后的每一项都是前面两项之和. (sap labs面试题,要求用不同的方法在白板上写abap算法...毫无心理准备,第一遍写了一个递归,可能是复杂度不太好,面试官让我再写一个,于是写了如下代码) PARAMETERS: p_number TYPE i OBLIGATORY. DATA : x TYPE i VALUE 0, y TYPE i VALUE 1. " 算法1 CASE p_number. WHE

高级算法——动态规划(斐波那契函数实例)

//使用递归去解决问题虽然简洁, 但效率不高,转为动态规划较好 function recurFib(n) {//斐波那契数列——递归 if (n <= 2) { return 1; } else { return recurFib(n - 1) + recurFib(n - 2); } } function dynFib(n) {//斐波那契数列——动态规划 var val = []; if (n == 1 || n == 2) { return 1; } else { val[1] = 1;

4月5日--关于算法的练习题--斐波那契数--杨辉三角形

/*要求:定义一个函数,接受一个正整数,返回该参数对应的斐波那契数介绍:斐波那契数前2个数都是1 ,从第三个开始都是前2个数之和,如下:1 .1.2.3.5.8.13.21.34--*/ <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <script type="text

算法——动态规划篇——斐波那契数

契数列,又称黄金切割数列.指的是这样一个数列:0.1.1.2.3.5.8.13.21.--在数学上.斐波纳契数列以例如以下被以递归的方法定义:F0=0.F1=1,Fn=F(n-1)+F(n-2)(n>=2.n∈N*)在现代物理.准晶体结构.化学等领域,斐波纳契数列都有直接的应用,为此.美国数学会从1960年代起出版了<斐波纳契数列>季刊,专门刊载这方面的研究成果. 以上内容来自百度百科.. 今天主要是想用动态规划的思想求解斐波那契数列.用来观察动态规划带来的优势,空间换时间.不反复求解

16、【常见算法】查找斐波那契数列的第N项

问题:手写一个函数,用于查找斐波那契数列的第N项目 1 /* 2 查找斐波那契数列的第N个数 3 */ 4 #include <iostream> 5 6 using namespace std; 7 8 int Find(int n) 9 { 10 int a, b; 11 a = 0; 12 b = 1; 13 14 15 for(int i = 1; i < n; i++) 16 { 17 int c = a + b; 18 a = b; 19 b = c; 20 } 21 ret