T1--最长公共前缀(lcp)

定义两个字符串S,T 的最长公共前缀lcp(S,T)为最长的字符串R,满足R 既是S 的前缀又是T 的前缀。
给定一个字符串S,下标从1 开始,每次询问给出四个正整数a,b,c,d,你需要输出[a,b]这个子串与[c,d]这个子串的lcp 的长度。

解法

暴力60分不用说了,那么正解可以用扩展\(kmp\),或者是万能字符串处理方法\(hash\)。但是我不会扩展\(kmp\),所以我就只用\(hash\)来乱搞一下。
那么二分查找这个前缀的长度,每次用\(hash\)检查一下,总的时间复杂度就是\(O(nlogn)\)。

ac代码

# include <cstdio>
# include <cstring>
# include <algorithm>
# include <ctype.h>
# include <iostream>
# include <cmath>
# include <map>
# include <vector>
# include <queue>
# define LL long long
# define ms(a,b) memset(a,b,sizeof(a))
# define ri (register int)
# define inf (0x7f7f7f7f)
# define pb push_back
# define fi first
# define se second
# define pii pair<int,int>
using namespace std;
inline int gi(){
    int w=0,x=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return w?-x:x;
}
# define N 100005
const int Mod=1e9+7,Base=127;
LL f[N],hash[N];
int n,m;
char s[N];
LL get_hash(int l,int r){
    return (f[r]-f[l-1]*hash[r-l+1]%Mod+Mod)%Mod;
}
int query(int a,int b,int c,int d){
    int l=1,r=b-a+1,res=0;
    if (d-c+1<r) r=d-c+1;
    while (l<=r){
        int mid=(l+r)>>1;
        if (get_hash(a,a+mid-1)==get_hash(c,c+mid-1)) l=mid+1,res=mid;
        else r=mid-1;
    }
    return res;
}
int main(){
    n=gi(),m=gi();
    scanf("%s",s+1);
    hash[0]=1;
    for (int i=1;i<=n;i++) hash[i]=hash[i-1]*(LL)Base%Mod;
    for (int i=1;i<=n;i++) f[i]=(f[i-1]*(LL)Base+s[i])%Mod;
    while (m--){
        int a=gi(),b=gi(),c=gi(),d=gi();
        printf("%d\n",query(a,b,c,d));
    }
    return 0;
}

T2--抢救粮仓(save)

查尔明的家着火啦!他的粮仓正面临着被烧毁的危险!
查尔明在山上一共建有n 个粮仓,按海拔从高到低依次被标记上编号1 到n,且没有任意两个粮仓的海拔是一样的。第i 个粮仓里藏有a[i]吨粮食,第i 个粮仓与第i-1 个粮仓之间的距离为1。
查尔明立马掏出水枪进行灭火,每次灭火他可以指定一个粮仓进行抢救,由于不同粮仓的火势不同,需要喷的水量也不同,抢救第i 个粮仓需要消耗b[i]吨水。查尔明的手速实在是太快了,你可以理解成灭火是瞬间完成的。与此同时,查尔明的助手们开着货车去转移粮食,因为他们认为越低的地方越安全,所以他们只会把粮食从高处运往低处,最终运到某个被灭过火的粮仓。查尔明的粮食很奇怪,每个粮仓都有一个共享值d[i],表示第i 个粮仓只能容纳与距自己距离不超过d[i]的粮仓的粮食,否则就会发生爆炸,所以在运输的过程中务必要避免发生爆炸。
已知水费和粮食运输费都为1 元/吨,查尔明想知道,自己最少需要花费多少钱来抢救全部粮食?

解法

一开始没有想到用dp,就打了一个三个特判。当\(n<=1000\)时,按照从低到高依次遍历,如果可以直接灭掉,那么就直接灭掉,然后再用这个点来更新后面的其他节点,我们更新的就是最小值,在判断。第二种情况是\(d_i=n\),那么也就是所有的节点都可以更新其他的所有节点,那么就暴力取最小值。

但是这只是\(70\)分,那么如果要拿到接下来的30分,我们就需要用\(dp\),\(f[i]\)表示前\(i\)个仓库需要的最小代价。转移方程就是:\(f[i]=min(f[j]-sum[j])+sum[i-1]+b[i](j>=i-d[i]-1)\),这个意思就是可以从\(j\),这个j是在i的范围内,加上他能够带来的代价,再取上最小值。

这个最小值可以用单调队列来维护或者是用树状数组或者是线段树来维护。

ac代码

# include <cstdio>
# include <cstring>
# include <algorithm>
# include <ctype.h>
# include <iostream>
# include <cmath>
# include <map>
# include <vector>
# include <queue>
# define LL long long
# define ms(a,b) memset(a,b,sizeof(a))
# define ri (register int)
# define inf (0x7f7f7f7f)
# define pb push_back
# define fi first
# define se second
# define pii pair<int,int>
using namespace std;
inline int gi(){
    int w=0,x=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return w?-x:x;
}
# define N 100005
int q[N],f[N],a[N],b[N],d[N],sum[N];
int n,tail,head;
int find(int x){
    int l=head,r=tail-1,res;
    while (l<=r){
        int mid=(l+r)>>1;
        if (q[mid]<x) l=mid+1;
        else r=mid-1,res=mid;
    }
    return q[res];
}
int main(){
    n=gi();
    for (int i=1;i<=n;i++) a[i]=gi(),sum[i]=sum[i-1]+a[i];
    for (int i=1;i<=n;i++) b[i]=gi();
    for (int i=1;i<=n;i++) d[i]=gi();
    q[tail++]=0;
    for (int i=1;i<=n;i++){
        int p=find(i-d[i]-1);
        f[i]=f[p]-sum[p]+b[i]+sum[i-1];
        while (head<tail&&f[q[tail-1]]-sum[q[tail-1]]>=f[i]-sum[i]) tail--;
        q[tail++]=i;
    }
    printf("%d\n",f[n]);
    return 0;
}

T3--幸运7(seven)

查尔明为了锻炼自己的观察力,在纸上画了一棵有n 个节点的树,点与点之间通过边连接,每条边有一个正整数权值。查尔明想要用肉眼观察出有多少组(i,j)满足1<=i<j<=n,且i 到j 的距离是他的幸运数7 的倍数。

查尔明不一会儿就观察出来了,但是他不知道自己的答案是否正确,你能写一个程序帮助他检验自己的答案吗?

解法

这道题太水了,原题是聪聪可可,点分治或者是树形dp。

点分治在我的xio讲堂里有讲到过,讲一下如何用树形dp来做。

定义:\(f[i][j]\)表示以第\(i\)为根节点的子树,到根节点距离除以7的余数\(j\)的节点的个数。

转移方程就是:\(f[i][j]=f[son][((j-len)%7+7%7]\),\(son\)是\(i\)节点的儿子,\(len\)是\(i\)到\(son\)之间的长度。

答案\(ans\)需要在递归的时候累加出来,\(ans=f[son][(-j-len)%7]*f[u][j]\),。

ac代码

# include <cstdio>
# include <cstring>
# include <algorithm>
# include <ctype.h>
# include <iostream>
# include <cmath>
# include <map>
# define LL long long
# define ms(a,b) memset(a,b,sizeof(a))
# define ri (register int)
# define inf (0x7f7f7f7f)
# define pb push_back
# define fi first
# define se second
# define pii pair<int,int>
using namespace std;
inline int gi(){
    int w=0,x=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return w?-x:x;
}
# define N 100005
struct edge{
    int to,nt,w;
}E[N<<1];
LL f[N][7];
int H[N];
int cnt,n;
LL ans;
void addedge(int u,int v,int w){
    E[++cnt]=(edge){v,H[u],w}; H[u]=cnt;
}
void dfs(int u,int fa){
    f[u][0]=1;
    for (int e=H[u];e;e=E[e].nt){
        int v=E[e].to,w=E[e].w;
        if (v==fa) continue;
        dfs(v,u);
        for (int i=0;i<7;i++) ans+=f[v][i]*f[u][((-i-w)%7+7)%7]*2;
        for (int i=0;i<7;i++) f[u][((i+w)%7+7)%7]+=f[v][i];
    }
}
int main(){
    n=gi();
    for (int i=1;i<n;i++){
        int u=gi(),v=gi(),w=gi();
        addedge(u,v,w); addedge(v,u,w);
    }
    ans=0; dfs(1,0);
    printf("%lld\n",ans/2);
    return 0;
}

[hgoi#2019/3/3]赛后总结的更多相关文章

  1. [hgoi#2019/3/10]赛后总结

    关于本次hg模拟赛,题目来源于CF1110. t1-无意义运算符(meaning) 题目描述 最大公约数和位运算之间有共同点吗?是时候来研究一下了. 给定一个正整数a,请找到一个闭区间[1,a-1] ...

  2. 「HGOI#2019.4.19省选模拟赛」赛后总结

    t1-Painting 这道题目比较简单,但是我比较弱就只是写了一个链表合并和区间DP. 别人的贪心吊打我的DP,嘤嘤嘤. #include <bits/stdc++.h> #define ...

  3. [hgoi#2019/3/21]NOIP&NOI赛后总结

    前言 今天做的是是2010年提高组和NOI的题目,做过几道原题,但是还是爆炸了,我真的太弱了. t1-乌龟棋 https://www.luogu.org/problemnew/show/P1541 这 ...

  4. [hgoi#2019/2/16t3]psolve

    题目描述 Dustar有n道题目要做.他的月薪是m元. 由于题目是一流的难题,所以Dustar不得不找个人来帮(代)助(替)他写作业. 找人写作业不是免费的,但是他们能保证在一个月内做出任何题目.每做 ...

  5. [hgoi#2019/2/16t2]friend

    题目描述 在一个遥远的国度里有n个人,每个人手上写着4个互不相同的数. 这个国度比较奇怪,如果两个人至少有一个数字相同,则他们是一对朋友. 现在这n个人按序号从左到右排成了一排,每个人都想知道在他左边 ...

  6. [hgoi#2019/2/16t1]math

    题目描述 解法 我们稍微枚举一下前面几位,可以得到这样的规律. \[X_i=\frac{1}{2^{i+1}-1}\] \[Y_i=\frac{1}{2^{2^i}-1}\] 那么要使\(xm=yn\ ...

  7. [hgoi#2019/2/24]玄学考试

    感想 对于这次考试,真的不想说什么了,太玄学了!!! t1输出比标准输出长,这是什么操作???难道要关文件???但是交到oj上又A掉了.这是什么操作. t2还好,没有出什么意外...但是要吐槽一下出题 ...

  8. [hgoi#2019/2/18]比较水

    T1--调换纸牌(card) Alex有 n张纸牌,每张纸牌上都有一个值ai,Alex把这些纸牌排成一排,希望将纸牌按值从小到大的顺序排好.现在他把这个任务交给你,你只能进行一种操作:选中一张牌,然后 ...

  9. [hgoi#2019/2/17t1]million

    题目描述 面对格鲁的入侵,小黄人们要组建一支队伍,来抵御进攻,现在有编号为1 至n 的小黄人,任命编号为n 的队长,由其挑选队员,当然编号不是随便编的,每一个编号里都包含一个小黄人的个人信息,现在队长 ...

随机推荐

  1. python 常见矩阵运算

    python 的 numpy 库提供矩阵运算的功能,因此我们在需要矩阵运算的时候,需要导入 numpy 的包. 1.numpy 的导入和使用 from numpy import *;#导入numpy的 ...

  2. ARM-GPIO

    操作GPIO有三种方法: 调用库函数读取IO的输入电平:uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef*GPIOx,uint16_t GPIO_pin): 操作寄 ...

  3. 置换群 Burnside引理 Pólya定理(Polya)

    置换群 设\(N\)表示组合方案集合.如用两种颜色染四个格子,则\(N=\{\{0,0,0,0\},\{0,0,0,1\},\{0,0,1,0\},...,\{1,1,1,1\}\}\),\(|N|= ...

  4. 第二次作业 对VC++6.0编译软件的评价

    首先这个软件伴随着我们很长时间了,它是我们一上大学最先接触的,也是应用相当多的一个软件,其实在最初的时候,我对编译软件的理解非常有限,觉得它能实现一个代码的功能十分神奇的一件事情,虽然彼时我们写的代码 ...

  5. 附加题(一)——interesting的抄袭现象

    这次的作业很有意思,是让我们搜索抄袭的同学的个人总结,并让我们列出链接,时间,作者及原因.其实我不是很能理解,抄袭现象是可耻的不受推崇的这是无可厚非,但是为什么要求我们大部分没有抄袭的同学去探究抄袭同 ...

  6. Finished yeah!

    终于到了最后的博客阶段,这时候才知道博客此时此刻是多么的惬意,它成了书写心声的自由平台!耗时一天完成这作业说起来也是蛮辛苦的,编译器需要新装,IDE需要熟悉,当然最主要的是之前浅入浅出的C++功底在此 ...

  7. Linux内核分析(第七周)

    可执行程序的装载 一.预处理.编译.链接和目标文件的格式 1.可执行程序怎么来的? 预处理: gcc -E -o hello.cpp hello.c -m32 *负责把include的文件包含进来及宏 ...

  8. TestSushu1

    https://github.com/jzjaerui/Individual-Project/blob/master/TestSushu1   <程序设计实践I> 题目:          ...

  9. Eclipse 项目有红感叹号

    问题原因]:工程中classpath中指向的包路径错误 [解决办法]:右键项目名称 BuildPath ---> Configure Build Paht...中,然后上面有几个选项卡找到 Li ...

  10. Cron任务调度CronNET

    Cron任务调度CronNET 阅读目录 1.Cron介绍和工具 2.CronNET介绍和使用 3.cron-expression-descriptor使用 4.资源 如果用知乎,可以关注专栏:.NE ...