NOIP2018提高组省一冲奖班模测训练(五)

http://www.51nod.com/Contest/ContestDescription.html#!#contestId=79

今天有点浪……

第一题想了一个多小时想到了正解,然后敲到一半就去看lol总决赛了(恭喜IG!!!!!!)

然后就没有然后了……

A 循环

小D站在一个长度为n的环,环上的位置从0到n-1编号。位置0与位置n-1相邻。对于一个位置i,

小D只能跳到距离位置i不超过R[i]的位置上。

可以顺时针也可以逆时针跳。比如当n=5,R[1]=2时,小D可以跳到的位置集合为{4,0,1,2,3}。 一开始小D站在位置s,

他的终点是位置t。假设每跳一次需要单位时间1。你能求出小D跳到终点的最少需要时间吗?假如无解则输出-1。

注意因为输入规模比较大,R由以下方式生成。

R[i]=(R[i-1]×g+seed)mod~p

其中R[0],g,seed,p是给定的。

 

输入

第一行给定三个整数,n,s,t。
第二行给定四个整数R[0],g,seed,p。 【数据规模与约定】
对于20%的数据,n≤100
对于40%的数据,n≤1000
对于60%的数据,1≤n≤10^5
对于100%的数据,1≤n≤10^7,0≤s,t<n,1≤p≤n,0≤R[0],g,seed<p

输出

输出一行一个整数,表示最短时间。

输入样例

9 0 2
1 3 4 7

输出样例

2


刚看到这道题,我发现我好像很久很久很久以前做过???

不过肯定当时是抄题解的,印象不深,没怎么理解。

或者其实我没有做过,我自己yy罢了

首先我一开始去观察那个公式的性质

然后发现没什么规律

貌似就是为了输入方便……

然后我就考虑一个点所能达到的区间

画个图出来发现貌似是用贪心解决区间问题???

然后仔细想想好像不是

一个很显然的思路就是每次要跳到最远

然后我就画了几下,发现貌似之前搜过的点就不用再搜了

所以每一个点最多会被检查过一次,复杂度是O(n)的,可以过1e7的数据

但是我发现这涉及到跨越区间的问题(如从n-1跳到0),不好搞

而且s和t的大小关系也不确定

感觉不好实现,感觉会比较复杂

然后就硬着头皮去写,写了没多久,一看时间哇靠比赛要开始了,然后……

后来讲解我看到了标程的写法,在一些处理上非常有技巧性

我需要学习学习。代码有注释

#include<bits/stdc++.h>
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std; const int MAXN = 1e7 + ;
int R[MAXN], a[MAXN], n, s, t;
int g, seed, p, ans;
bool val[MAXN]; int main()
{
scanf("%d%d%d%d%d%d%d", &n, &s, &t, &R[], &g, &seed, &p);
REP(i, , n) R[i] = (1ll * R[i-] * g + seed) % p;
REP(i, s, n) a[i - s] = R[i]; //a数组的作用就是把整个数组等价转化成以0为起点,方便后面处理
REP(i, , s) a[i - s + n] = R[i];
t = (t - s + n) % n; //注意这里s和t大小不确定 int l = , r = ;
_for(ans, , n)
{
if(l + n <= t || t <= r) { printf("%d\n", ans); return ; } //注意这里是或,可以画图理解
int pl = l, pr = r; //注意l是负的,但是一旦作为数组的下标就要加上n
_for(i, pl, )
{
if(val[i + n]) break; //val[i]表示i这个点有没有遍历过
l = min(l, i - a[i + n]), r = max(r, i + a[i + n]), val[i + n] = ;
}
for(int i = pr; i >= ; i--)
{
if(val[i]) break;
l = min(l, i - a[i]), r = max(r, i + a[i]), val[i] = ;
}
}
puts("-1"); return ;
}

小D的老师给了小D一大堆的字符串。具体来说,小D现在得到了N个字符串, 第i个字符串为S_i。对于小D来说,

他最喜欢的字符串就是回文串了。 一个串是回文串,当且仅当它倒过来和本身相同。比如abaaba倒过来还是abaaba,

而xyz倒过来是zyx,所以abaaba是回文串而xyz不是。 小D是个有创造力的孩子。他决定尝试把这些串两两拼接。

假如一次拼接后得到的串是回文的,他会非常开心。现在他想问你他最多能开心多少次?

形式化来说,小D想知道,有多少对二元组(i,j),满足i≠j,S_i+S_j是回文串。其中+表示字符串的前后拼接。

比如aa+ab=aaab。注意假如(i,j)和(j,i)都是满足条件的,那么答案算两次。

输入

第一行包含一个整数n。
接下来n行,每行给定一个字符串S_i。 【数据规模与约定】
对于20%的数据,字符串总长不超过2000。
对于40%的数据,n≤1000
另外有20%的数据,所有字符串长度均相同。
对于100%的数据,1≤n≤10^5,字符串总长度不超过10^5。字符串只包含小写字母。

输出

输出一个整数,表示答案。

输入样例

8
abaccabaab
accaba
abacc
ab
ba
aba
ccaba
abaaba

输出样例

14

这道题好艰辛……
写了N久 看到题目,字符总长已经提示会用到trie了
而且1e5要不是nlogn,要不是n
而有关字符串里面复杂度是O(n)的很容易想到trie
提示已经很明显了 正解是trie+哈希,非常的巧妙
我们考虑两个字符串
ab
ccba
这两个拼起来是abccba是一个回文串
那么回文串去掉两端也是回文串
所以我们把ccba拆成cc ba
可以用trie判断ab和ba,用哈希判断cc是否是回文串(正串与反串的哈希值相等即为回文串)
这是大致思路
那么我们可以预处理每个串的每个前缀是不是回文串,用哈希,复杂度为字符总数
然后每次把当前串倒着去trie上遍历,如果遍历一个位置,之前是回文串,那么更新答案
然后再加入当前串
如果我们按照下标的顺序去这样处理的话
可以发现会漏掉一些情况
如果这样得出的字符满足
i < j ,i + j是回文串
显然还有三种情况
i < j ,j + i是回文串
i > j ,i + j是回文串
i > j ,j + i是回文串
对于i > j可以改变枚举的顺序
对于j+i,可以把串取反再去做(这个时候如果两个串长度相同会算两次,要特判)
因为如果j + i是回文串
那么i取反的ii,j取反的jj
ii + jj也是回文串
很神奇,其实可以证明
比如ab + ccba
取反交换相加即
abcc + ba
也是回文串
#include<bits/stdc++.h>
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std; typedef unsigned long long ull;
const int MAXN = 1e5 + ;
const int base = ; int trie[MAXN][], tot;
int flag[MAXN], n;
string s[MAXN];
ull p[MAXN], hash[MAXN][], cnt[MAXN], ans; void init()
{
tot = ;
memset(cnt, , sizeof(cnt));
memset(trie, , sizeof(trie));
} void Insert(string s)
{
int p = , len = s.length();
REP(i, , len)
{
int ch = s[i] - 'a';
if(!trie[p][ch]) trie[p][ch] = ++tot;
p = trie[p][ch];
}
cnt[p]++;
} void Search(string s, int op)
{
int p = , len = s.length();
for(int i = len - ; i >= ; i--)
{
int ch = s[i] - 'a';
if(!trie[p][ch]) return;
p = trie[p][ch];
if((op || i) && (!i || flag[i - ])) ans += cnt[p];
}
} inline ull val(int l, int r, int k)
{
return hash[r][k] - (l - < ? : hash[l-][k]) * p[r - l + ];
} void solve(int op)
{
init();
_for(k, , n)
{
string str = s[k];
int len = str.length();
hash[][] = str[] - 'a';
hash[][] = str[len-] - 'a'; REP(i, , len)
{
hash[i][] = hash[i-][] * base + str[i] - 'a';
hash[i][] = hash[i-][] * base + str[len-i-] - 'a';
}
REP(i, , len) flag[i] = (val(, i, ) == val(len - i - , len - , ) ? : ); Search(str, op);
Insert(str);
}
} int main()
{
ios::sync_with_stdio(false);
cin >> n;
_for(i, , n) cin >> s[i];
p[] = ; _for(i, , MAXN) p[i] = p[i-] * base; solve();
reverse(s + , s + n + ); solve();
_for(i, , n) reverse(s[i].begin(), s[i].end()); solve();
reverse(s + , s + n + ); solve(); printf("%llu\n", ans);
return ;
}
第三题不会,不想改了……


NOIP2018提高组省一冲奖班模测训练(五)的更多相关文章

  1. NOIP2018提高组省一冲奖班模测训练(六)

    NOIP2018提高组省一冲奖班模测训练(六) https://www.51nod.com/Contest/ContestDescription.html#!#contestId=80 20分钟AC掉 ...

  2. NOIP2018提高组省一冲奖班模测训练(四)

    NOIP2018提高组省一冲奖班模测训练(四) 这次比赛只AC了第一题,而且花了40多分钟,貌似是A掉第一题里面最晚的 而且还有一个半小时我就放弃了…… 下次即使想不出也要坚持到最后 第二题没思路 第 ...

  3. NOIP2018提高组省一冲奖班模测训练(三)

    NOIP2018提高组省一冲奖班模测训练(三) 自己按照noip的方式考,只在最后一两分钟交了一次 第一题过了,对拍拍到尾. 第二题不会.考试时往组合计数的方向想,推公式,推了一个多小时,大脑爆炸,还 ...

  4. NOIP2018提高组省一冲奖班模测训练(二)

    比赛链接 NOIP2018提高组省一冲奖班模测训练(二) 今天发挥正常,昨天不在状态…… 花了很久A了第一题 第二题打了30分暴力 第三题投机取巧输出test1答案(连暴力都不知道怎么打,太弱了) 2 ...

  5. NOIP2018提高组省一冲奖班模测训练(一)

    比赛链接 https://www.51nod.com/contest/problemList.html#!contestId=72&randomCode=147206 这次考试的题非常有质量 ...

  6. [51Nod]NOIP2018提高组省一冲奖班模测训练(三) 题解

    链接 A.Anan的派对 题意:Anan想举办一个派对.Anan的朋友总共有 n 人.第i个人如果参加派对会得到 \(c_i\) 的快乐值,除他自己外每多一个人参加他会减少 \(d_i\) 的快乐值. ...

  7. [51Nod]NOIP2018提高组省一冲奖班模测训练(四)翻车记+题解

    链接 下午5点的时候,突然想起来有这个比赛,看看还有一个小时,打算来AK一下,结果因为最近智商越来越低,翻车了,我还是太菜了.上来10分钟先切掉了C和A,结果卡在了B题,唉. A.砍树 一眼题,两遍树 ...

  8. [51Nod]NOIP2018提高组省一冲奖班模测训练(二)

    http://www.51nod.com/contest/problemList.html#!contestId=73&randomCode=4408520896354389006 还是原题大 ...

  9. [51Nod]NOIP2018提高组省一冲奖班模测训练(一)题解

    http://www.51nod.com/contest/problemList.html#!contestId=72&randomCode=147206 原题水题大赛.. A.珂朵莉的旅行 ...

随机推荐

  1. 分享一个iOS输入框特殊限制的代码 UITextField (Validation)

    //个人总结.欢迎新增或改动 #import <UIKit/UIKit.h> typedef enum{ VALIDATION_TYPE_NUM_VALIDATED = 0,//数字 VA ...

  2. leetcode || 56、 Merge Intervals

    problem: Given a collection of intervals, merge all overlapping intervals. For example, Given [1,3], ...

  3. ssh无法连接到远端Ubuntu的解决方法

    近日,饱受无法远程登录到新安装在VMWare上的Ubuntu虚拟机,现在发现问题所在.故记录此问题的解决方式,以备后用. 一.远程登录虚拟机的准备: Ubuntu虚拟机的联网方式应该选择Bridged ...

  4. nyoj--106--背包问题(贪心,水题)

    背包问题 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 现在有很多物品(它们是可以分割的),我们知道它们每个物品的单位重量的价值v和重量w(1<=v,w<= ...

  5. 【POJ 3744】 Scout YYF I

    [题目链接] http://poj.org/problem?id=3744 [算法] 概率DP + 矩阵乘法 [代码] #include <algorithm> #include < ...

  6. Nginx实现负载均衡 + Keepalived实现Nginx的高可用

    前言 使用集群是大中型网站解决高并发.海量数据问题的常用手段.当一台服务器的处理能力.存储空间不足时,不要企图去换更强大的服务器,对大型网站而言,不管多么强大的服务器,都满足不了网站持续增长的业务需求 ...

  7. linux编译安装gdb7.10.1

    1.下载GDB7.10.1安装包 #wget http://ftp.gnu.org/gnu/gdb/gdb-7.10.1.tar.gz 2.解压 #.tar.gz 3.创建安装目录 #/ #cd /u ...

  8. Core篇——初探IdentityServer4(客户端模式,密码模式)

    Core篇——初探IdentityServer4(客户端模式,密码模式) 目录 1.Oatuth2协议的客户端模式介绍2.IdentityServer4客户端模式实现3.Oatuth2协议的密码模式介 ...

  9. Centos7下Docker的使用

    一.安装Docker 1.1.查看原有系统是否已经安装docker yum list installed | grep docker 1.2.如果有则不需要继续安装,想重新安装,先卸载 yum -y ...

  10. chrome打开控制台状态下,没有人为打断点,自动进入断点模式的解决方法

    如下图所示:在控制台去掉Sources -> XHR/fetch Breakpoints -> Any XHR or fetch 的勾