A Simple Problem with Integers

这个题目首先要打表找规律,这个对2018取模最后都会进入一个循环节,这个循环节的打表要用到龟兔赛跑。

龟兔赛跑算法 floyed判环算法

这个算法我觉得还是很有意思的,可以学习一下。

不过这个题目这个算法打表还是有点难写的。

由这个算法可以得到这个循环节的最大长度是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 循环节 修改 平方 找规律 线段树的更多相关文章

  1. poj 3468 A Simple Problem with Integers(原来是一道简单的线段树区间修改用来练练splay)

    题目链接:http://poj.org/problem?id=3468 题解:splay功能比线段树强大当然代价就是有些操作比线段树慢,这题用splay实现的比线段树慢上一倍.线段树用lazy标记差不 ...

  2. POJ-3468-A Simple Problem with Integers(区间更新,求和)-splay或线段树

    区间更新求和 主要用来练习splay树区间更新问题 //splay树的题解 // File Name: 3468-splay.cpp // Author: Zlbing // Created Time ...

  3. HDU 2522 A simple problem( 分数循环节 )

    链接:Here! 思路:模拟除法,当余数再次出现的时候一定是遇到了循环节( 可看下图例子 ),否则的话继续除法的步骤,直到被除数为 0 . 注意:这道题不需要重新申请一个数组来单独存放答案,如果符合要 ...

  4. poj3468 A Simple Problem with Integers(zkw区间修改模板)

    此题是一道线段树的裸题,这里只是为了保存我的zkw线段树模板 #include <cstdio> #include <cstring> #include <iostrea ...

  5. 线段树---poj3468 A Simple Problem with Integers:成段增减:区间求和

    poj3468 A Simple Problem with Integers 题意:O(-1) 思路:O(-1) 线段树功能:update:成段增减 query:区间求和 Sample Input 1 ...

  6. poj 3468:A Simple Problem with Integers(线段树,区间修改求和)

    A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 58269   ...

  7. A Simple Problem with Integers 多树状数组分割,区间修改,单点求职。 hdu 4267

    A Simple Problem with Integers Time Limit: 5000/1500 MS (Java/Others)    Memory Limit: 32768/32768 K ...

  8. A Simple Problem with Integers poj 3468 多树状数组解决区间修改问题。

    A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 69589   ...

  9. poj 3468 A Simple Problem with Integers【线段树区间修改】

    A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 79137   ...

随机推荐

  1. 分享一本Java并发编程的免费好书

    最近当当的大促销又开始了,估计很多人脑子一热,又花钱囤了不少技术书吧. 在我看来大部分程序员买技术书的用途(以下排名按用途从大到小): 让领导.同事看见,你看我多爱学习: 给自己一个心理安慰,我还没废 ...

  2. tf.nn.sigmoid_cross_entropy_with_logits 分类

    tf.nn.sigmoid_cross_entropy_with_logits(_sentinel=None,,labels=None,logits=None,name=None) logits和la ...

  3. 数据结构和算法(Golang实现)(24)排序算法-优先队列及堆排序

    优先队列及堆排序 堆排序(Heap Sort)由威尔士-加拿大计算机科学家J. W. J. Williams在1964年发明,它利用了二叉堆(A binary heap)的性质实现了排序,并证明了二叉 ...

  4. Redis分布式锁的实现以及工具类

    一.应用场景: 本文应用的场景为在查询数据时,发现数据不存在此时就需要去查询数据库并且更新缓存,此时可能存在高并发的请求同时打在数据库上,而针对这种情况必须要给这些请求加锁,故而采用了分布式锁的方式. ...

  5. Salesforce 开发 | Salesforce与微信集成实操指南

    配置前须知 Salesforce通过试点对特定客户提供Lightning WeChat Messaging,该试点需要同意特定的条款.除非Salesforce宣布WeChat Messaging全面可 ...

  6. 复习python的多态,类的内部权限调用 整理

    #多态的用法 class Dii: passclass Aii(Dii): def run(self): print('一号函数已调用')class Bii(Dii): def run(Dii): p ...

  7. python高级特性之封包与解包

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:kwsy PS:如有需要Python学习资料的小伙伴可以加点击下方链接 ...

  8. Treasure Island DFS +存图

    All of us love treasures, right? That's why young Vasya is heading for a Treasure Island. Treasure I ...

  9. Java 8 到 Java 14,改变了哪些你写代码的方式?

    前几天,JDK 14 正式发布了,这次发布的新版本一共包含了16个新的特性. 其实,从Java8 到 Java14 ,真正的改变了程序员写代码的方式的特性并不多,我们这篇文章就来看一下都有哪些. La ...

  10. Linux命令:chown

    说明: 将指定文件的拥有者改为指定的用户或组. 语法: chown [-cfhvR] [--help] [--version] user[:group] file... 参数: user : 新的文件 ...