A Simple Problem with Integers 循环节 修改 平方 找规律 线段树
A Simple Problem with Integers
这个题目首先要打表找规律,这个对2018取模最后都会进入一个循环节,这个循环节的打表要用到龟兔赛跑。
这个算法我觉得还是很有意思的,可以学习一下。
不过这个题目这个算法打表还是有点难写的。
由这个算法可以得到这个循环节的最大长度是6 最大入环距离是4.
为什么有些循环节不是6,还是可以用6呢,因为每个元素平方最大周期为6,且6是其他所有周期的公倍数。
然后学完之后还是不太会这个题目怎么写,2018 ACM-ICPC 上海大都会 H A Simple Problem with Integers(level 4)(线段树+floyd判环+暴力)
研究了一下这个人的代码,才稍微会了一点点。
这个题目首先是要判断有没有进入负环,如果一个区间的所有叶子节点都已经进入循环节,tim数组
那么这个以后就可以用延迟标记直接记录这个已经推到了这个数的循环节的第几个,mark数组
推到了循环节的第几个可以用pos数组记录,pos数组
然后就是建树,用一个二维的数组来记录,第二维是pos,代表这个数要返回的循环节的位置。
知道这些就可以自己敲代码了。
敲代码的时候越发感觉这个代码写的巧妙之处了,首先它预处理了0~2017 这样之后就可以不用求一个数的平方了,直接迭代。
然后就是这个pos数组,如果来不及push_up 就要求输出结果,这个就已经记录了,然后可以通过这个pos数组来push_up
然后就是这个树的第二维,第二维记录了从这个往后推的6个数,而且每次push_up一次就会把第二维的第一个位置更新为我们所要的结果。
这个题目很好,代码也很巧妙,值得学习。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
#include <map>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn = 5e4 + ;
const int mod = ;
ll mp[maxn], a[maxn];
ll tree[maxn * ][];
int tim[maxn * ], pos[maxn * ], lazy[maxn * ]; void push_up(int id)
{
for (int i = ; i < ; i++)//这个for循环保证i==0的位置就是答案,并且推出了后面的五个位置的数
//这个的主要目的是因为只有在叶子节点的pos才会有值,只要不是叶子节点就都初始化为0,所以我们要保证tree[id][0]的位置就是答案
tree[id][i] = tree[id << ][(pos[id << ] + i) % ] + tree[id << | ][(pos[id<<|] + i) % ];
tim[id] = min(tim[id << ], tim[id << | ]);
pos[id] = ;//为什么这个地方可以赋值为0呢,因为上面的那层for循环已经保证了i==0 的位置就是答案
// printf("tree[%d][0]=%lld\n", id, tree[id][0]);
} void build(int id,int l,int r)
{
tim[id] = pos[id] = lazy[id] = ;
if(l==r)
{
tree[id][] = a[l];//一开始a[l]就是查询结果
for (int i = ; i < ; i++) tree[id][i] = mp[tree[id][i - ]];//这个就是在找a[l]的平方,a[l]平方的平方...
return;
}
int mid = (l + r) >> ;
build(id << , l, mid);
build(id << | , mid + , r);
push_up(id);
} void push_down(int id)
{
pos[id << ] = (pos[id << ] + lazy[id]) % ;
pos[id << | ] = (pos[id << | ] + lazy[id]) % ;
lazy[id << ] += lazy[id];
lazy[id << | ] += lazy[id];
lazy[id] = ;
} void update(int id,int l,int r,int x,int y)
{
if (y<l || x>r) return;
if(x<=l&&y>=r&&tim[id]>)
{
lazy[id]++;
pos[id] = (pos[id] + ) % ;//为什么这个地方不求出结果,因为求不出来,这个只可以往下传递lazy 标志,并且记录这个是在循环节的哪一个位置
//然后这个位置的上一个节点被更新,或者说这个pos记录就是一种表示求结果的方式,因为之后输出的就是tree[id][pos[id]]
return;
}
if(l==r)
{
pos[id] = ;//如果还是在暴力的阶段就必须赋值为0,pos 和 lazy 只有在进入循环节之后才会有
lazy[id] = ;
tim[id]++;
tree[id][] = mp[tree[id][]];
for (int i = ; i < ; i++) tree[id][i] = mp[tree[id][i - ]];
return;
}
push_down(id);
int mid = (l + r) >> ;
if (x <= mid) update(id << , l, mid, x, y);
if (y > mid) update(id << | , mid + , r, x, y);
push_up(id);
} ll query(int id,int l,int r,int x,int y)
{
if (x > r || y < l) return ;
// printf("id=%d l=%d r=%d x=%d y=%d\n", id, l, r, x, y);
if (x <= l && y >= r) return tree[id][pos[id]];
int mid = (l + r) >> ;
push_down(id);
ll ans = ;
if (x <= mid) ans = query(id << , l, mid, x, y);
if (y > mid) ans += query(id << | , mid + , r, x, y);
return ans;
} int main()
{
for (int i = ; i < ; i++) mp[i] = i * i%mod;
int t;
scanf("%d", &t);
for(int cas=;cas<=t;cas++)
{
int n, m;
scanf("%d", &n);
for (int i = ; i <= n; i++) scanf("%lld", &a[i]);
build(, , n);
scanf("%d", &m);
printf("Case #%d:\n",cas);
while (m--) {
char s[];
int l, r;
scanf("%s%d%d", s, &l, &r);
if (l > r) swap(l, r);
if (s[] == 'Q') {
ll ans = query(, , n, l, r);
printf("%lld\n", ans);
}
else update(, , n, l, r);
}
}
return ;
}
A Simple Problem with Integers 循环节 修改 平方 找规律 线段树的更多相关文章
- poj 3468 A Simple Problem with Integers(原来是一道简单的线段树区间修改用来练练splay)
题目链接:http://poj.org/problem?id=3468 题解:splay功能比线段树强大当然代价就是有些操作比线段树慢,这题用splay实现的比线段树慢上一倍.线段树用lazy标记差不 ...
- POJ-3468-A Simple Problem with Integers(区间更新,求和)-splay或线段树
区间更新求和 主要用来练习splay树区间更新问题 //splay树的题解 // File Name: 3468-splay.cpp // Author: Zlbing // Created Time ...
- HDU 2522 A simple problem( 分数循环节 )
链接:Here! 思路:模拟除法,当余数再次出现的时候一定是遇到了循环节( 可看下图例子 ),否则的话继续除法的步骤,直到被除数为 0 . 注意:这道题不需要重新申请一个数组来单独存放答案,如果符合要 ...
- poj3468 A Simple Problem with Integers(zkw区间修改模板)
此题是一道线段树的裸题,这里只是为了保存我的zkw线段树模板 #include <cstdio> #include <cstring> #include <iostrea ...
- 线段树---poj3468 A Simple Problem with Integers:成段增减:区间求和
poj3468 A Simple Problem with Integers 题意:O(-1) 思路:O(-1) 线段树功能:update:成段增减 query:区间求和 Sample Input 1 ...
- poj 3468:A Simple Problem with Integers(线段树,区间修改求和)
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 58269 ...
- A Simple Problem with Integers 多树状数组分割,区间修改,单点求职。 hdu 4267
A Simple Problem with Integers Time Limit: 5000/1500 MS (Java/Others) Memory Limit: 32768/32768 K ...
- A Simple Problem with Integers poj 3468 多树状数组解决区间修改问题。
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 69589 ...
- poj 3468 A Simple Problem with Integers【线段树区间修改】
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 79137 ...
随机推荐
- Mysql基础知识一
1.数据库的定义 数据:描述事物符号记录.(包括数字.文字.图形.图像.声音.档案记录等)以记录形式统一的格式进行存储. 广义上的数据:出现在计算机内部的一切二进制数据流都为数据 狭义上的数据:只是数 ...
- 如果我选择IT行业,会不会在几年,或者几年后被社会给淘汰??
IT互联网各行业薪资占比,你能拿到多少?随着移动互联网时代的发展,IT行业的需求量也越来越大,而且每年都会新增,当然也会有淘汰. 人生如此之短,都不喜欢自己虚度光阴,也不希望自己所努力的东西成为历史, ...
- stand up meeting 12-9
今天项目小组本已约好在今天下午四点半进行今天的daily scrum: 但是在四点半的时候,天赋和士杰同学均因组内项目会议延时,导致今天的daily scrum只能在晚上进行,但静雯同学因身体不舒服无 ...
- E - Max Sum Plus Plus Plus HDU - 1244 (线性区间DP)
题目大意: 值得注意的一点是题目要求的是这些子段之间的最大整数和.注意和Max Sum Plus Plus这个题目的区别. 题解: 线性区间DP,对每一段考虑取或者不取.定义状态dp[i][j]指的 ...
- 详解 通道 (Channel 接口)
在本篇博文中,本人主要讲解NIO 的两个核心点 -- 缓冲区(Buffer) 和 通道 (Channel)之一的 缓冲区(Buffer), 有关NIO流的其他知识点请观看本人博文<详解 NIO流 ...
- web测试流程
1.立项后测试需要拿到文档(需求说明书,原型图,接口文档,) 2.需求评审 3.用例编写(主流程,备流程,异常流,业务规则,正常类,异常类,页面检查) 测试用例编写方法(等价类划分,边界值分析法,错误 ...
- phpstudy之访问loaclhost显示目录
phpstudy版本:phpstudy2018 具体操作: 当前版本的默认设置访问网站根目录是不会显示目录的,需要我们设置,其实也很简单,只需两步就可以搞定 1.找到phpstudy目录下的www文件 ...
- 文本序列化【通用】word2sequence,文本序列字典保存
''' 文本序列化 ''' class WordSequence(): UNK_TAG = "<UNK>" PAD_TAG = "<PAD>&qu ...
- keras数据集读取
from tensorflow.python import keras (x_train,y_train),(x_test,y_test) = keras.datasets.cifar100.load ...
- 进阶 Linux基本命令-2
mkdir -p /a/b/c/d -p 循环创建目录yum install tree -y ...