[机房练习赛7.26] YYR字符串
1 无尽的矩阵(matrix.c/cpp/pas)
1.1 题目描述
从前有一个的小矩阵,矩阵的每个元素是一个字母(区分大小写),突然有一天它发生了变异,覆盖了整个二维空间,即不停自我复制产生相同的矩阵然后无隙放置。现在二维空间已经被它占领了,但你只被告知了大小为R*C空间的内容(可能包含不完整的原矩阵),为了将它恢复原状,你需要找到满足条件的面积最小的原矩阵。
奇怪的是,同时有 T 个二维空间发生了变异,你需要尽快解决这些变异。
1.2 输入格式
第一行为一个整数T,表示二维空间数目。
接下来T组数据。每组数据第一行包含两个数 R,C,表示你被告知的空间大小;接下来 R 行,每行包含 C 个字母,表示你被告知的空间内容。
1.3 输出格式
对于每一组数据输出一行,每行只包含一个数,表示最小的原矩阵面积。
1.4 样例输入
2
2 5
ABABA
ABABA
2 8
ABCDEFAB
AAAABAAA
1.5 样例输出
2
12
1.6 数据范围与约定
对于前20%的数据R<=20,C<=20;
对于前40%的数据R<=400,C<=100;
对于100%的数据R<=5000 ,C<=100,T<=50。
将每一行hash 为一个数,对得到的新数组直接跑KMP 求最小循环节长度,列
同理。将两次求得的最小循环节长度相乘即为答案。这就是std 做法。
满分
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
char s[][];
int line,row,T,nxt[],r,c;
void get1( int x ){
nxt[] = -;
int i = , j = -;
while( i < c ){
if( s[x][i] == s[x][j] || j == - ){
i++; j++;
nxt[i] = j;
}
else j = nxt[j];
}
}
void get2( int x ){
nxt[] = -;
int i = , j = -;
while( i < r ){
if( s[i][x] == s[j][x] || j == - ){
i++; j++;
nxt[i] = j;
}
else j = nxt[j];
}
}
int main(){
freopen("matrix.in","r",stdin);
freopen("matrix.out","w",stdout);
scanf("%d", &T);
while( T-- ){
line = row = ;
scanf("%d%d", &r, &c);
for( int i = ; i < r; i++ ){
scanf("%s", s[i]);
get1(i);
line = max(line,c-nxt[c]);
}
for( int i = ; i < c; i++ ){
get2(i);
row = max(row,r-nxt[r]);
}
printf("%d\n",row*line);
}
}
std:
#include<iostream>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; int R , C ;
char A[][] ;
unsigned long long base= , h_r[] , h_c[] , zj[] ;
int len , fail[] ; char get_c(){
char c;
while((c=(char)getchar())!=EOF) if(!isspace(c)) break ;
return c;
} int get_it(){
memset(fail,,sizeof(fail)) ;
for(int i=;i<=len;++i){
int t=fail[i-] ;
while(t && zj[t+]!=zj[i]) t=fail[t] ;
if(zj[t+]==zj[i]) fail[i]=t+ ;
}
return len-fail[len] ;
} void solve(){
scanf("%d%d",&R,&C);
memset(h_r,,sizeof(h_r)) ; memset(h_c,,sizeof(h_c)) ;
for(int i=;i<=R;++i) for(int j=;j<=C;++j) A[i][j]=get_c() , h_r[i]=h_r[i]*base+A[i][j] ;
for(int j=;j<=C;++j) for(int i=;i<=R;++i) h_c[j]=h_c[j]*base+A[i][j] ;
for(int i=;i<=R;++i) zj[i]=h_r[i] ;
len=R ;
int ans=get_it() ;
for(int i=;i<=C;++i) zj[i]=h_c[i] ;
len=C ;
ans*=get_it() ;
cout << ans << '\n' ;
} int main(){
freopen("matrix.in","r",stdin) ;
freopen("matrix.out","w",stdout) ;
int T;
scanf("%d",&T) ;
for(int i=;i<=T;++i) solve() ;
//fprintf(stderr,"std: %d\n",clock()) ;
return ;
}
2 异或(xor.c/cpp/pas)
2.1 题目描述
给出 n 个数,Q次询问,每次问[l,r]中最大连续异或和。
为了体现在线操作,对于每次询问(x,y):
l=min( ((x+lastans) mod n)+1 , ((y+lastans) mod n)+1 )
r=max( ((x+lastans) mod n)+1 , ((y+lastans) mod n)+1 )
2.2 输入格式
第一行为两个整数n,m,分别表示数的个数和询问次数。
接下来一行 n个数,再接下来 m行,每行两个数 x,y,表示给出询问(x,y),通过上述操作得到l和r,查询[l,r]中最大连续异或和。
2.3 输出格式
输出m行,每行一个整数表示该次询问的答案。
2.4 样例输入
3 3
1 4 3
0 1
0 1
4 3
2.5 样例输出
5
7
7
2.6 数据范围与约定
对于30%的数据,n<=500,Q<=500。
对于100%的数据,n<=12000 , Q<=6000 , 给出的数均在signed longint 范围内。
同bzoj1741
将 n 个数分成sqrt(n)个块。考虑用 w[i][j] 表示从第 i 个块开头元素到第 j 个元素这
个区间中,最大连续异或和。建可持久化Trie 树并且预处理出w 数组。预处理复杂度为 O(n
* sqrt(n) * 位数)。
查询[l,r]时,令 p 为 l 以右第一个块开头元素,那么首先可以直接得到 p 到 r 区间的
答案。再考虑上 [l,p-1] 区间中的元素,逐个在可持久化Trie 上贪心即可。查询总复杂度为
O(Q * sqrt(n) * 位数)。
std:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=;
const int maxbit=;
int N,M,A[maxn];
int tr[maxn];
struct PerTrie
{
int next[][],num[];
int id;
void init(){ id=next[][]=next[][]=num[]=; }
int f(int x,int i){ return (x>>i)&; }
void Insert(int& rt,int pre,int x,int pos) //插入
{
rt=++id;
next[rt][]=next[pre][];
next[rt][]=next[pre][];
num[rt]=num[pre]+;
if(pos==-) return;
int d=f(x,pos);
Insert(next[rt][d],next[pre][d],x,pos-);
}
int MaxXor(int l,int r,int x) //查询最大异或值,因为A[i]保存
{ //的是前缀异或值,所以得到的结果就是某一段区间的异或值
int ret=;
for(int i=maxbit;i>=;i--)
{
int d=f(x,i);
int a=next[l][d^],b=next[r][d^];
if(num[b]-num[a]>) ret|=(<<i),l=a,r=b;
else l=next[l][d],r=next[r][d];
}
return ret;
}
}PT;
int block,num,bel[maxn],dp[][maxn]; //dp保存第几块到第几个数的区间最大异或值
void init()
{
tr[]=;
PT.init();
for(int i=;i<=N;i++) PT.Insert(tr[i],tr[i-],A[i],maxbit); //插入
block=(int)sqrt(N+0.5);
num=N/block;
if(N%block) num++; //加1
memset(dp,,sizeof(dp));
bel[]=;
for(int i=;i<=N;i++) bel[i]=(i-)/block+; //记录下属于哪个块
for(int i=;i<=num;i++)
{
int st=(i-)*block+;
for(int j=st;j<=N;j++)
{
dp[i][j]=max(dp[i][j-],A[j]^A[st-]); //可能是[st,j]这段区间
dp[i][j]=max(dp[i][j],PT.MaxXor(tr[st-],tr[j],A[j])); //再找最大的
}
}
}
int GetAns(int l,int r)
{
l--;
int s=bel[l],ret=;
if(bel[r]>s) ret=dp[s+][r]; //查询从后面一个块开始的
for(int i=l;i<=min(r,s*block);i++)
{
ret=max(ret,PT.MaxXor(tr[l-],tr[r],A[i]));
}
return ret;
}
int main()
{
freopen("xor.in","r",stdin) ;
freopen("xor.out","w",stdout) ;
scanf("%d%d",&N,&M);
A[]=;
int x;
for(int i=;i<=N;i++)
{
scanf("%d",&x);
A[i]=A[i-]^x;
}
init();
int last=,l,r;
while(M--)
{
scanf("%d%d",&l,&r);
l=(l+(LL)last)%N+;
r=(r+(LL)last)%N+;
if(l>r) swap(l,r);
//printf("%d %d\n",l,r);
last=GetAns(l,r);
printf("%d\n",last);
}
return ;
}
满分
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define LL long long
#define N 12005
#define T 200
int n,m,block,t,sz,root,l,r,x,y,ans;
int a[N],s[N],f[T][N],g[T][N],L[N],R[N],ls[N*],rs[N*];
void insert( int &k, int x, int dep ){
if( !k ) k = ++sz;
if( dep == - ) return;
int d = x>>dep&;
if( d == ) insert(ls[k],x,dep-);
else insert(rs[k],x,dep-);
}
void query(int k,int x,int dep){
if( !k ) return;
if( dep == - ) return;
int d = x>>dep&;
if( d == ){
if( rs[k] ) ans |= <<dep, query(rs[k],x,dep-);
else query(ls[k],x,dep-);
}if( d == ){
if( ls[k] ) ans |= <<dep, query(ls[k],x,dep-);
else query(rs[k],x,dep-);
}
}
void ask(int l,int r){
int numl = (l-)/block+, numr = (r-)/block+;
if( numl == numr ){
for( int i = l-; i <= r; i++ ) for( int j = i+; j <= r; j++ ) ans = max(ans,s[i]^s[j]); return;
}
for( int i = l-; i <= R[numl]; i++ ) for( int j = L[numr]; j <= r; j++ ) ans = max( ans, s[i]^s[j] );
for( int i = numl+; i <= numr; i++ ) ans = max(ans,f[i][r]);
for( int i = numr-; i >= numl; i-- ) ans = max(ans,g[i][l]);
return;
}
int main(){
freopen("xor.in","r",stdin);
freopen("xor.out","w",stdout);
scanf("%d%d", &n, &m);
for( int i = ; i <= n; i++ ) scanf("%d", &a[i]), s[i] = s[i-]^a[i]; s[n+] = s[n];
block = sqrt(n*); t = (n-)/block+;
L[] = ; R[] = block;
for( int i = ; i <= t; i++ ) L[i] = L[i-]+block, R[i] = R[i-]+block; R[t]=n;
for( int i = ; i <= t; i++ ){
sz = root = ;
memset(ls,,sizeof(ls));
memset(rs,,sizeof(rs));
for( int j = L[i]; j <= n; j++ ){
insert( root, s[n]^s[j-], );
ans=; query( root, s[n]^s[j], );
f[i][j] = max(ans,f[i][j-]);
}
}
for( int i = t; i; i-- ){
sz = root = ;
memset(ls,,sizeof(ls));
memset(rs,,sizeof(rs));
for( int j = R[i]; j; j-- ){
insert( root, s[j], );
ans = ; query( root, s[j-], );
g[i][j] = max(ans,g[i][j+]);
}
}
ans = ;
for( int i = ; i <= m; i++ ){
scanf("%d%d", &l, &r);
l = ((ll)l+(ll)ans)%n+; r = ((ll)r+(ll)ans)%n+;
if(l>r) swap(l,r);
ans = ; ask(l,r);
printf("%d\n",ans);
}
return ;
}
3魔法串(magic.c/cpp/pas)
3.1 题目描述
给你一棵n+1个结点的有根树,结点从0到n标号,其中0为根结点。
这是一棵魔法树。这棵树的每条边有一个魔力值,同一个结点连向不同子结点的边的魔力值不同。一个结点所代表的魔法串是从根一直走到这个结点,经过的魔力值依次排列形成的有序序列,另外,一个串是魔法串当且仅当它被一个结点所代表。
现在,为了使用强大的魔法,你需要对每个魔法串,找到最长的是它后缀的魔法串。为了方便输出,你只需要输出代表这个魔法串的结点的标号即可。若没有这个魔法串,请输出0。
3.2 输入格式
第一行一个整数n,代表除根以外的结点个数。
第二行 n个整数,第i个整数P_i代表标号为i的结点的父亲标号。
第三行 n个整数,第i个整数C_i代表标号为i的结点连向父亲的边的魔力值。
3.3 输出格式
输出一行n个整数,第i个整数表示第i个结点代表的魔法串的答案。
3.4 样例输入
7
0 0 1 1 2 4 5
1 2 3 2 1 1 3
3.5 样例输出
0 0 02 1 5 3
3.6 数据范围与约定
对于30%的数据,保证1<=n<=2000。
对于100%的数据,保证1<=n<=200000,0<=P_i<i,1<=C_i<=n。
用AC自动机直接跳会TLE,MLE,用主席树维护
考虑补全AC 自动机(Trie 图),考虑一个结点u 所连出的转移边与fail[u]所
连出的转移边的关系,只有u 直接连出的边会影响这些转移边,而边数是n-1 条。于是我
们考虑将fail[u]的转移边全部复制给u,再在此基础上对u 的转移边进行修改。这个如何实
现?用可持久化线段树维护每个结点的转移边即可。
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std ;
const int N = + ;
struct Edge{ int to,v,next; }e[N*];
int last[N],cnt,fail[N],q[N],p[N],c[N],n,head,tail,root[N],ls[N*],rs[N*],v[N*],sz;
void insert( int u, int v, int w ){
e[++cnt].to = v; e[cnt].v = w; e[cnt].next= last[u]; last[u] = cnt;
}
void modify( int &k, int l, int r, int p, int val ){
ls[++sz] = ls[k]; rs[sz] = rs[k]; v[sz] = v[k]; k = sz;
if( l == r ){ v[k] = val; return; }
int mid = (l+r)>>;
p<=mid ? modify( ls[k], l, mid, p, val ) : modify( rs[k], mid+, r, p, val );
}
int query( int k, int l, int r, int p ){
if( l == r ) return v[k];
int mid = (l+r)>>;
return p<=mid ? query( ls[k], l, mid, p ) : query( rs[k], mid+, r, p );
}
int main(){
freopen("magic.in","r",stdin);
freopen("magic.out","w",stdout);
scanf("%d", &n);
for( int i = ; i <= n; i++ ) scanf("%d", &p[i]);
for( int i = ; i <= n; i++ ) scanf("%d", &c[i]), insert(p[i],i,c[i]);
q[] = ; tail = ;
while( head != tail ){
int now = q[head++];
root[now] = root[fail[now]];
for( int i = last[now]; i; i = e[i].next )
fail[q[tail++]=e[i].to] = query(root[fail[now]],,n,e[i].v), modify(root[now],,n,e[i].v,e[i].to);
}
for( int i = ; i <= n; i++ ) printf("%d ", fail[i] );
return ;
}
[机房练习赛7.26] YYR字符串的更多相关文章
- 【python之路26】字符串之格式化%和format
Python基础之杂货铺 字符串格式化 Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式, ...
- 牛客练习赛37-筱玛的字符串-DP递推
筱玛的字符串 思路 :dp [ i ] [ j ] [ 3 ] 分别代表到第 i 位时 左括号比右括号多 j ,后面有三个状态 分别表示当前位置 S3的字符 是正在反转的,还是 反转完成的,还是没有反 ...
- hihocoder编程练习赛91:相邻字符串
题目链接 给定一个长度小于1e5的字符串s,s中字符全是大写英语字母.现在要寻找s中有多少组邻近的"hio"字符串,邻近的定义如下:hi距离+io距离+ho距离小于k.输入k和s, ...
- wannafly 练习赛11 B 假的字符串(字典树+建边找环)
链接:https://www.nowcoder.com/acm/contest/59/B 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言65536K 64bit ...
- 2018.03.26 Python-Pandas 字符串常用方法
import numpy as np import pandas as pd 1 #字符串常用方法 - strip s = pd.Series([' jack ','jill',' jease ',' ...
- hihocoder offer收割编程练习赛11 A hiho字符串
思路: 我用的尺取. 注意题目描述为恰好2个'h',1个'i',1个'o'. 实现: #include <iostream> #include <cstdio> #includ ...
- 14.Object-C--浅谈Foundation框架字符串NSString 与NSMutableString
OC的字符串时经常使用到的,今天我对于OC字符串做一个简单的总结,如果有错误之处,麻烦留言指正.感谢! NSString是一个不可变长度的字符串对象.表示它初始化以后,你不能改变该变量所分配的内存中的 ...
- LintCode 字符串比较
比较两个字符串A和B,确定A中是否包含B中所有的字符.字符串A和B中的字符都是大写字母: 给出 A = "ABCD" B = "AABC", 返回 false ...
- 004-Python字符串
Python 字符串(str) 字符串是 Python 中最常用的数据类型.我们可以使用引号('或")来创建字符串.创建字符串很简单,只要为变量分配一个值即可. var1 = "H ...
随机推荐
- 201521123034《Java程序设计》第六周学习总结
1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 注1:关键词与内容不求多,但概念之间的联系要清晰,内容覆盖 ...
- 201521123040 《Java程序设计》第6周学习总结
1.本章学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 2. 书面作业 clone方法1.1 Object对象中的c ...
- 201521123051《java程序设计》 第五周学习总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 使用工具:XMind 2. 书面作业 1.代码阅读:Child压缩包内源代码 1.1 com.parent包中Child.ja ...
- 201521145048《Java程序设计》第4周学习总结
1. 本章学习总结 学会了如何去设计一个类,尽量用private修饰属性,public修饰方法. 了解继承的目的. 了解继承和多态的关系. 了解关键字extends super final overr ...
- 201521123010 《Java程序设计》第14周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 2. 书面作业 1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自 ...
- php中获取当前系统时间、时间戳
今天写下otime($time, $now)为将时间格式转为时间戳,$time为必填.清楚了这个,想了解更多,请继续往下看. 3. date($format)用法比如:echo date(‘Y-m-d ...
- Eclipse rap 富客户端开发总结(9) : rap上传与下载
一 上传 上传即将文件上传到服务器上,在客户端需要写相应的脚本,服务器端需要注册相应的 handle 接受客户端的请求. 原理: Rap 的上传和下载是通过普通的 web 的方式进行上传和下载的 , ...
- Log4j.properties属性文件
log4j.properties文件属性介绍log4j.rootLogger = [ level ] , appenderName1, appenderName2, …#level : 设定日志记录的 ...
- Wrong FS: hdfs://......, expected: file:///
单机版使用的是FileSystem类的静态函数: FileSystem hdfs = FileSystem.get(conf) 伪分布式下需要使用Path来获得 Path path = new Pat ...
- 业余草通告CSDN博客用户zhang__ao非法转载文章的公告
今天早上有粉丝给我反馈,CSDN的一位用户大量非法的转载了我的个人网站:业余草(www.xttblog.com)上的大量文章.现一对该用户转载业余草上网站上的所有文章进行了举报! 从上图中可以看出,该 ...