1. 程式人生 > >Codeforces Round #223 (Div. 2): C. Sereja and Prefixes(二分+遞迴)

Codeforces Round #223 (Div. 2): C. Sereja and Prefixes(二分+遞迴)

題意:

你有一個序列,一開始為空,之後進行m次操作,操作有兩種:

  • 1 x:在當前序列後面新增一個數x
  • 2 x, y:將序列的前x個數複製y遍接序列後面(x<10000)

之後n次詢問,每次詢問位置p上面的數字是多少,保證p不超過序列長度

思路:

對於每次詢問,直接暴力遞迴當前位置上的數字是哪次操作①新增的就行了,因為複製操作每次只會複製前10000個數字,所以遞迴次數不會超過15次(遞迴時可能需要用到二分)

當然也可以直接記下來前10000個數字是多少, 這樣應該就是線性的了

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<string>
#include<math.h>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
#define LL long long
#define mod 1000000007
typedef struct Res
{
	int op;
	int x, y;
	LL l, r;
}Res;
Res s[200005];
int Gao(int p, LL x)
{
	int l, r, m;
	if(s[p].op==1)
		return s[p].x;
	else
	{
		r = x-s[p].l+1;
		x = (r-1)%s[p].x+1;
		l = 1, r = p-1;
		while(l<r)
		{
			m = (l+r+1)/2;
			if(x<s[m].l)
				r = m-1;
			else
				l = m;
		}
		return Gao(r, x);
	}
}
int main(void)
{
	LL now, p;
	int m, n, i, R;
	scanf("%d", &m);
	for(i=1;i<=m;i++)
	{
		scanf("%d", &s[i].op);
		if(s[i].op==1)
			scanf("%d", &s[i].x);
		else
			scanf("%d%d", &s[i].x, &s[i].y);
	}
	R = now = 0;
	scanf("%d", &n);
	for(i=1;i<=n;i++)
	{
		scanf("%lld", &p);
		while(R!=m && p>now)
		{
			R++;
			s[R].l = now+1;
			if(s[R].op==1)
				s[R].r = s[R].l;
			else
				s[R].r = s[R].x*s[R].y+now;
			now = s[R].r;
		}
		printf("%d ", Gao(R, p));
	}
	puts("");
	return 0;
}