无尽的矩阵(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 ;
}

异或(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字符串的更多相关文章

  1. 【python之路26】字符串之格式化%和format

    Python基础之杂货铺   字符串格式化 Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式, ...

  2. 牛客练习赛37-筱玛的字符串-DP递推

    筱玛的字符串 思路 :dp [ i ] [ j ] [ 3 ] 分别代表到第 i 位时 左括号比右括号多 j ,后面有三个状态 分别表示当前位置 S3的字符 是正在反转的,还是 反转完成的,还是没有反 ...

  3. hihocoder编程练习赛91:相邻字符串

    题目链接 给定一个长度小于1e5的字符串s,s中字符全是大写英语字母.现在要寻找s中有多少组邻近的"hio"字符串,邻近的定义如下:hi距离+io距离+ho距离小于k.输入k和s, ...

  4. wannafly 练习赛11 B 假的字符串(字典树+建边找环)

    链接:https://www.nowcoder.com/acm/contest/59/B 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言65536K 64bit ...

  5. 2018.03.26 Python-Pandas 字符串常用方法

    import numpy as np import pandas as pd 1 #字符串常用方法 - strip s = pd.Series([' jack ','jill',' jease ',' ...

  6. hihocoder offer收割编程练习赛11 A hiho字符串

    思路: 我用的尺取. 注意题目描述为恰好2个'h',1个'i',1个'o'. 实现: #include <iostream> #include <cstdio> #includ ...

  7. 14.Object-C--浅谈Foundation框架字符串NSString 与NSMutableString

    OC的字符串时经常使用到的,今天我对于OC字符串做一个简单的总结,如果有错误之处,麻烦留言指正.感谢! NSString是一个不可变长度的字符串对象.表示它初始化以后,你不能改变该变量所分配的内存中的 ...

  8. LintCode 字符串比较

    比较两个字符串A和B,确定A中是否包含B中所有的字符.字符串A和B中的字符都是大写字母: 给出 A = "ABCD" B = "AABC", 返回 false ...

  9. 004-Python字符串

    Python 字符串(str) 字符串是 Python 中最常用的数据类型.我们可以使用引号('或")来创建字符串.创建字符串很简单,只要为变量分配一个值即可. var1 = "H ...

随机推荐

  1. 201521123034《Java程序设计》第六周学习总结

    1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 注1:关键词与内容不求多,但概念之间的联系要清晰,内容覆盖 ...

  2. 201521123040 《Java程序设计》第6周学习总结

    1.本章学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 2. 书面作业 clone方法1.1 Object对象中的c ...

  3. 201521123051《java程序设计》 第五周学习总结

    1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 使用工具:XMind 2. 书面作业 1.代码阅读:Child压缩包内源代码 1.1 com.parent包中Child.ja ...

  4. 201521145048《Java程序设计》第4周学习总结

    1. 本章学习总结 学会了如何去设计一个类,尽量用private修饰属性,public修饰方法. 了解继承的目的. 了解继承和多态的关系. 了解关键字extends super final overr ...

  5. 201521123010 《Java程序设计》第14周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 2. 书面作业 1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自 ...

  6. php中获取当前系统时间、时间戳

    今天写下otime($time, $now)为将时间格式转为时间戳,$time为必填.清楚了这个,想了解更多,请继续往下看. 3. date($format)用法比如:echo date(‘Y-m-d ...

  7. Eclipse rap 富客户端开发总结(9) : rap上传与下载

    一 上传 上传即将文件上传到服务器上,在客户端需要写相应的脚本,服务器端需要注册相应的 handle 接受客户端的请求. 原理: Rap 的上传和下载是通过普通的 web 的方式进行上传和下载的 ,  ...

  8. Log4j.properties属性文件

    log4j.properties文件属性介绍log4j.rootLogger = [ level ] , appenderName1, appenderName2, …#level : 设定日志记录的 ...

  9. Wrong FS: hdfs://......, expected: file:///

    单机版使用的是FileSystem类的静态函数: FileSystem hdfs = FileSystem.get(conf) 伪分布式下需要使用Path来获得 Path path = new Pat ...

  10. 业余草通告CSDN博客用户zhang__ao非法转载文章的公告

    今天早上有粉丝给我反馈,CSDN的一位用户大量非法的转载了我的个人网站:业余草(www.xttblog.com)上的大量文章.现一对该用户转载业余草上网站上的所有文章进行了举报! 从上图中可以看出,该 ...