用户工具

站点工具


2020-2021:teams:die_java:front_page_springtraining5

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
2020-2021:teams:die_java:front_page_springtraining5 [2020/05/15 22:25]
fyhssgss update
2020-2021:teams:die_java:front_page_springtraining5 [2020/05/23 12:10] (当前版本)
fyhssgss [训练详情]
行 3: 行 3:
 [[https://​vjudge.net/​contest/​373163|比赛网址]] [[https://​vjudge.net/​contest/​373163|比赛网址]]
  
-===== 训练结果 ​===== +===== 训练详情 ​===== 
- +  * 时间:​2020-5-10 13:00~18:00 
-  * rank:算了这个别说了 +  * rank: 
-  * 完成情况:3/​6/​13+  * 完成情况:''​%%3/6/13%%''​
  
 ===== 题解 ===== ===== 题解 =====
行 13: 行 13:
 补题 补题
  
-==== 题意 ​====+=== 题意 ===
  
 给了一个序列,要求实现两种操作 给了一个序列,要求实现两种操作
行 22: 行 22:
 === 题解 === === 题解 ===
  
-开始想到线段树套线性基,发现时间和空间都爆了。后发现我们可以记录 $a[1...i]$ 的线性基,添加时候则从高位到低位,尽量用当前的基去替换之前的基,这样能使所有的基离r更近。查询的时候只用位置大于 $l$ 的基。+开始想到线段树套线性基,发现时间和空间都爆了。后发现我们可以记录 $a[1... i]$ 的线性基,添加时候则从高位到低位,尽量用当前的基去替换之前的基,这样能使所有的基离r更近。查询的时候只用位置大于 $l$ 的基。
  
 +\\ 
 +<hidden B>
 <code cpp> <code cpp>
 #​include<​iostream>​ #​include<​iostream>​
行 109: 行 111:
 } }
 </​code>​ </​code>​
 +</​hidden>​
 +\\ 
 ===== D Vacation ===== ===== D Vacation =====
 solved by wxg solved by wxg
行 119: 行 123:
  
 可以想象,最后几辆车一定是贴在一起通过的,我们只需要枚举 $x$ ,计算最后 $x$ 俩车贴贴后通过时间,取一个最大值即可。 可以想象,最后几辆车一定是贴在一起通过的,我们只需要枚举 $x$ ,计算最后 $x$ 俩车贴贴后通过时间,取一个最大值即可。
 +\\  
 +<hidden D>
 <code cpp> <code cpp>
 #​include<​iostream>​ #​include<​iostream>​
行 155: 行 160:
 } }
 </​code>​ </​code>​
 +</​hidden>​
 +\\ 
 ===== E Path ===== ===== E Path =====
  
行 166: 行 173:
  
 求出最短路径的新图,可以看出答案为最小割 求出最短路径的新图,可以看出答案为最小割
 +\\ 
 +<hidden E>
 <code cpp> <code cpp>
 #​include<​iostream>​ #​include<​iostream>​
行 301: 行 310:
 } }
 </​code>​ </​code>​
 +</​hidden>​
 +\\ 
 ===== F Typewriter ===== ===== F Typewriter =====
  
 solved by wxg solved by wxg
-### 题意+=== 题意 ​===
  
 给了一个字符串,你现在要花最小代价构造出该字符串,有两种构造方法 给了一个字符串,你现在要花最小代价构造出该字符串,有两种构造方法
  
-1. 花 $p$ 代价在当前字符串后添加一个字符。 +  - 花 $p$ 代价在当前字符串后添加一个字符。 
-2. 花 $q$ 代价在当前字符串后添加一个当前字符串的字串+  ​- ​花 $q$ 代价在当前字符串后添加一个当前字符串的字串
  
-#### 题解+=== 题解 ​===
  
 dp ,$dp[i]$ 表示构造出长度 $i$ 的字符串的最小代价,有两种转移 dp ,$dp[i]$ 表示构造出长度 $i$ 的字符串的最小代价,有两种转移
  
-1. $dp[i]=dp[i-1]+p$  +  - $dp[i]=dp[i-1]+p$ 
-2. $dp[i]=dp[j]+q$ ​ , $j$ 为满足 $s[1...j]$ 中存在 $s[j+1...i]$ 的子串 ​ +  ​- ​$dp[i]=dp[j]+q$ , $j$ 为满足 $s[1... j]$ 中存在 $s[j+1... i]$ 的子串
  
-问题是 $j$ 怎么求? ​+问题是 $j$ 怎么求?
  
 首先随着 $i$ 增加,$j$ 是单调的 首先随着 $i$ 增加,$j$ 是单调的
  
-我们可以构建 $s[1...j]$ 的后缀自动机,当 dp 到 $i$ 时,我们在后缀自动机上匹配 $s[i]$ ,​若匹配长度与 $j$ 的和大于等于 $i$ ,说明 $j$ 不用增加,反之则增加 $j$ 直到大于等于为止。 +我们可以构建 $s[1... j]$ 的后缀自动机,当 dp 到 $i$ 时,我们在后缀自动机上匹配 $s[i]$ ,​若匹配长度与 $j$ 的和大于等于 $i$ ,说明 $j$ 不用增加,反之则增加 $j$ 直到大于等于为止。 
- +\\  
-````cpp+<hidden f> 
 +<​code ​cpp>
 #​include<​iostream>​ #​include<​iostream>​
 #​include<​cstdio>​ #​include<​cstdio>​
行 333: 行 345:
 int read() int read()
 { {
- int k=0,​f=1;​char c=getchar();​ +    ​int k=0,​f=1;​char c=getchar();​ 
- for(;​!isdigit(c);​c=getchar()) if(c=='​-'​) f=-1; +    for(;​!isdigit(c);​c=getchar()) if(c=='​-'​) f=-1; 
- for(;​isdigit(c);​c=getchar()) k=k*10+c-'​0';​return k*f;+    for(;​isdigit(c);​c=getchar()) k=k*10+c-'​0';​return k*f;
 } }
 const int N=400055; const int N=400055;
行 344: 行 356:
 void init() void init()
 { {
- for(int i=0;​i<​=tot;​i++) memset(ch[i],​0,​sizeof(ch[i]));​ +    ​for(int i=0;​i<​=tot;​i++) memset(ch[i],​0,​sizeof(ch[i]));​ 
- last=tot=0;​len[0]=0;​link[0]=-1;​+    last=tot=0;​len[0]=0;​link[0]=-1;​
 } }
 void extend(int c) void extend(int c)
 { {
- int cur=++tot,​p=last;​len[cur]=len[last]+1;​size[cur]=1;​ +    ​int cur=++tot,​p=last;​len[cur]=len[last]+1;​size[cur]=1;​ 
- for(;​p!=-1&&​!ch[p][c];​p=link[p]) ch[p][c]=cur;​ +    for(;​p!=-1&&​!ch[p][c];​p=link[p]) ch[p][c]=cur;​ 
- if(p==-1) link[cur]=0;​ +    if(p==-1) link[cur]=0;​ 
- else  +    else  
-+    
- int q=ch[p][c];​ +        int q=ch[p][c];​ 
- if(len[p]+1==len[q]) link[cur]=q;​ +        if(len[p]+1==len[q]) link[cur]=q;​ 
- else  +        else  
- +        
- int clone=++tot;​ +            int clone=++tot;​ 
- len[clone]=len[p]+1;​ +            len[clone]=len[p]+1;​ 
- link[clone]=link[q];​ +            link[clone]=link[q];​ 
- memcpy(ch[clone],​ch[q],​sizeof(ch[q]));​ +            memcpy(ch[clone],​ch[q],​sizeof(ch[q]));​ 
- for(;​p!=-1&&​ch[p][c]==q;​p=link[p])  +            for(;​p!=-1&&​ch[p][c]==q;​p=link[p])  
- ch[p][c]=clone;​ +                ch[p][c]=clone;​ 
- link[q]=clone;​link[cur]=clone;​ +            link[q]=clone;​link[cur]=clone;​ 
- +        
-+    
- last=cur;​ +    last=cur; 
-} +  ​
 int get(int p,int c,int opt) int get(int p,int c,int opt)
 { {
- if(ch[p][c])  +    ​if(ch[p][c])  
-+    
- p=ch[p][c];​ +        p=ch[p][c];​ 
- if(opt==1) mxlen++; +        if(opt==1) mxlen++; 
-+    
- else  +    else  
-+    
- while(p!=-1&&​!ch[p][c]) +        while(p!=-1&&​!ch[p][c]) 
- p=link[p];​ +            p=link[p];​ 
- if(p==-1) p=0,​mxlen=0;​  +        if(p==-1) p=0,​mxlen=0; ​  
- else mxlen=len[p]+1,​p=ch[p][c];​ +        else mxlen=len[p]+1,​p=ch[p][c];​ 
-+    
- if(opt) return mxlen; +    if(opt) return mxlen; 
- return p;+    return p;
 } }
 int main() int main()
 { {
- while(scanf("​%s",​s+1)!=EOF) +    ​while(scanf("​%s",​s+1)!=EOF) 
-+    
- int l=strlen(s+1);​ +        int l=strlen(s+1);​ 
- init();​scanf("​%d%d",&​P,&​Q);​ +        init();​scanf("​%d%d",&​P,&​Q);​ 
- int inslen=0,​pos=0;​mxlen=0;​ +        int inslen=0,​pos=0;​mxlen=0;​ 
- for(int i=1;​i<​=l;​i++) +        for(int i=1;​i<​=l;​i++) 
- +        
- dp[i]=dp[i-1]+P;​ +            dp[i]=dp[i-1]+P;​ 
- if(get(pos,​s[i]-'​a',​1)+inslen>​=i)  +            if(get(pos,​s[i]-'​a',​1)+inslen>​=i)  
- +            
- dp[i]=min(dp[i],​dp[inslen]+Q);​ +                dp[i]=min(dp[i],​dp[inslen]+Q);​ 
- pos=get(pos,​s[i]-'​a',​0);​ +                pos=get(pos,​s[i]-'​a',​0);​ 
- +            
- else  +            else  
- +            
- while(get(pos,​s[i]-'​a',​1)+inslen<​i) +                while(get(pos,​s[i]-'​a',​1)+inslen<​i) 
- +                
- extend(s[++inslen]-'​a'​);​ +                    extend(s[++inslen]-'​a'​);​ 
- +                
- pos=get(pos,​s[i]-'​a',​0);​ +                pos=get(pos,​s[i]-'​a',​0);​ 
- if(inslen<​i) +                if(inslen<​i) 
- dp[i]=min(dp[i],​dp[inslen]+Q);​ +                    dp[i]=min(dp[i],​dp[inslen]+Q);​ 
- +            
-// cout<<​inslen<<"​ "<<​mxlen<<​endl;​ +//          cout<<​inslen<<"​ "<<​mxlen<<​endl;​ 
- +        
- printf("​%lld\n",​ dp[l]); +        printf("​%lld\n",​ dp[l]); 
-+    
- return 0;+    return 0;
 } }
-```` +</​code>​ 
- +</​hidden>​ 
-## I String ​+\\  
 +===== I String ​=====
  
 补题 by hxm 补题 by hxm
-==== 题意 ​====+ 
 +=== 题意 ===
  
 给定一个只包含小写字母的字符串,要求选出一个长度为$K$的子序列,满足字典序最小,同时子序列中每个字母的出现次数都在一个各自给定的范围$[L,​R]$内 给定一个只包含小写字母的字符串,要求选出一个长度为$K$的子序列,满足字典序最小,同时子序列中每个字母的出现次数都在一个各自给定的范围$[L,​R]$内
行 431: 行 445:
  
 然后就完了。【很不明白比赛是怎么没调出来,,】 然后就完了。【很不明白比赛是怎么没调出来,,】
- +\\  
-<​code>​+<hidden I> 
 +<​code ​cpp>
 #​include<​algorithm>​ #​include<​algorithm>​
 #​include<​iostream>​ #​include<​iostream>​
行 519: 行 534:
 } }
 </​code>​ </​code>​
 +</​hidden>​
 +\\ 
 ===== K Function ===== ===== K Function =====
  
 补题 by fyh 补题 by fyh
-==== 题意 ​====+=== 题意 ===
  
 $$ $$
行 555: 行 572:
  
 注意,读入要用%%__%%int128,​但是在开数组的时候都要开int,否则会爆空间。 注意,读入要用%%__%%int128,​但是在开数组的时候都要开int,否则会爆空间。
 +\\ 
 +<hidden K>
 <code cpp> <code cpp>
 #​include<​bits/​stdc++.h>​ #​include<​bits/​stdc++.h>​
行 639: 行 658:
  
 </​code>​ </​code>​
 +</​hidden>​
 +\\ 
 ===== 训练实况 ===== ===== 训练实况 =====
  
2020-2021/teams/die_java/front_page_springtraining5.1589552758.txt.gz · 最后更改: 2020/05/15 22:25 由 fyhssgss