无尽的矩阵(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. C语言之算法初步(汉诺塔--递归算法)

    个人觉得汉诺塔这个递归算法比电子老鼠的难了一些,不过一旦理解了也还是可以的,其实网上也有很多代码,可以直接参考.记得大一开始时就做过汉诺塔的习题,但是那时代码写得很长很长,也是不理解递归的结果.现在想 ...

  2. 【Alpha】——Second Scrum Meeting

    一.今日站立式会议照片 二.每个人的工作 成员 昨天已完成的工作 今天计划完成的工作 李永豪 完成登录按钮代码 完成添加功能 郑靖涛 完成登录按钮代码 完成删除功能 杨海亮 完成注册按钮代码 完成查找 ...

  3. 201521123017 《Java程序设计》第7周学习总结

    1. 本周学习总结 2. 书面作业 Q1.ArrayList代码分析 1.1 解释ArrayList的contains源代码 1.2 解释E remove(int index)源代码 1.3 结合1. ...

  4. 201521123051《Java程序设计》第十一周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. Java多线程同步的方法: (1)同步方法:即有synchronized关键字修饰的方法. 由于java的每个对象 ...

  5. Markdown格式

    一个例子: 例子开始 1. 本章学习总结 今天主要学习了三个知识点 封装 继承 多态 2. 书面作业 Q1. java HelloWorld命令中,HelloWorld这个参数是什么含义? 今天学了一 ...

  6. 控制结构(5) 必经之地(using)

    // 上一篇:局部化(localization) // 下一篇:最近最少使用(LRU) 基于语言提供的基本控制结构,更好地组织和表达程序,需要良好的控制结构. 前情回顾 上一周,我们谈到了分支/卫语句 ...

  7. JSP引入 - UEditor 富文本编辑器

    UEditor  JSP 因为是项目第一天就导入了,现在过去一个多星期了,可能会有问题 官网:http://ueditor.baidu.com/website/ 1. 解压对应的UEditor压缩包至 ...

  8. 解决Maven管理的项目下"Missing artifact xxx bundle"问题

    例如使用maven编译使用了mina的包的工程,出现如下提示:  [INFO] Scanning for projects... [INFO]                             ...

  9. SpringMVC HelloWorld实例开发及部署

    SpringMVC HelloWorld实例开发及部署 2017-01-24 目录 1 Tomcat及Eclipse Tomcat插件安装配置  1.1 Tomcat的安装  1.2 Eclipse ...

  10. 静态页面如何实现 include 引入公用代码

    一直以来,我司的前端都是用 php 的 include 函数来实现引入 header .footer 这些公用代码的,就像下面这样: <!-- index.php --> <!DOC ...