当前位置:网站首页>2021-09-11 训练场补题
2021-09-11 训练场补题
2022-06-11 21:18:00 【dplovetree】
C - Family View
题意:
给你 n n n个模式串,模式串中只有小写字母,模式串长度之和 l e n < = 1 e 6 len<=1e6 len<=1e6,然后给你一个匹配串 l e n < = 1 e 6 len<=1e6 len<=1e6,匹配串由全字符集组成。要求将匹配串中的所有和模式串匹配的子段替换成 ‘*’ ;
思路:
优化AC自动机;普通的AC自动机在匹配的时候会暴力跳fail指针;也有建fail 树来统计每个匹配串在文本串中出现的次数的优化。但是这道题我们只用在匹配的地方加个标记,记录长度即可,想象原本跳fail的过程,对于自动机上每个fail节点,我们要对他的flag取max,然后加标记,那么我们在建fail边的时候,直接取max就好了,这样就不用跳fail边了。那么我们只要遍历自动机,如果当前文本串的字符不是字母,那么我们直接回到自动机的元节点即可。
结构体数组不要赋初值!默认会把全数组赋值,然后就MLE了。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=7e5+4;
int t,n;
struct node{
int son[26],fail=0,flag;
}trie[maxn];
int p[maxn];
int tot=1;
queue<int>q;
char s[maxn];
void init(){
tot=0;
for(int j=0;j<26;j++){
trie[tot].son[j]=0;
}
trie[tot].fail=0;
trie[tot].flag=0;
}
void insert(char *s){
int len=strlen(s),u=0;
for(int i=0;i<len;i++){
int v=s[i]-'a';
if(!trie[u].son[v]){
trie[u].son[v]=++tot;
for(int j=0;j<26;j++){
trie[tot].son[j]=0;
}
trie[tot].fail=0;
trie[tot].flag=0;
}
u=trie[u].son[v];
}
trie[u].flag=max(trie[u].flag,len);
}
void getfail(){
for(int i=0;i<26;i++)
if(trie[0].son[i])q.push(trie[0].son[i]);
while(!q.empty()){
int u=q.front();q.pop();
trie[u].flag=max(trie[u].flag,trie[trie[u].fail].flag);
for(int i=0;i<26;i++){
int v=trie[u].son[i];
int x=trie[u].fail;
if(!v){
trie[u].son[i]=trie[x].son[i];
}else{
trie[v].fail=trie[x].son[i];
q.push(v);
}
}
}
}
void query(char *s){
int u=0,len=strlen(s);
for(int i=0;i<len;i++)p[i]=0;
for(int i=0;i<len;i++){
int v=-1;
if(s[i]>='A'&&s[i]<='Z')v=s[i]-'A';
if(s[i]>='a'&&s[i]<='z')v=s[i]-'a';
if(v==-1)u=0;
else u=trie[u].son[v];
if(trie[u].flag){
p[i+1]--;
p[i-trie[u].flag+1]++;
}
}
int res=0;
for(int i=0;i<len;i++){
res+=p[i];
if(res==0)putchar(s[i]);
else putchar('*');
}
printf("\n");
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
init();
for(int i=1;i<=n;i++){
scanf("%s",s);
insert(s);
}
getfail();
getchar();
scanf("%[^\n]",s);
query(s);
}
return 0;
}
//D I K L
D - Tea
题意:
懒得写
思路:
分类讨论
看代码应该看得懂
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e6+4;
int t,n;
ll l,r;
ll ans=0;
int main(){
while(cin>>l>>r){
ans=1e18;
ll res=r-l;
if(res<=3)ans=2;
else ans=(res-3+1)/2+2;
if(r<=2)ans=1;
if(r<=1)ans=0;
if(l==0)ans=min(ans,(r+1)/2);
cout<<ans<<endl;
}
return 0;
}
//D I K L
I - Tower Defence
题意:
给你 n n n个节点的带边权的树( n < = 1 e 5 n<=1e5 n<=1e5),定义每次删除一个边,对答案的贡献是分开的两颗子树中直径的较大值。求分别删除每条边对答案的贡献和。
思路:
我们分成两种情况来考虑:
如果删除的边不是整棵树的直径上的边,那么对答案的贡献就还是整棵树的直径。
如果删除的边不是整棵树的直径,我们对两边子树的直径取较大值。
我们可以比较简单地证明出,删掉一条边之后,子树的直径一定是由原直径的端点出发的。(如果不是从端点出发的最长链,那么他就会取代现在端点的这条链,加入原直径)。
那么我们就可以预处理出删除直径上的一条边后,子树的最大直径,即对于每个点,求他不经过直径最远能延伸多少,然后左右分别做一次DP, d p [ i ] = m a x ( l e n , n o w + c n t ) dp[i]=max(len,now+cnt) dp[i]=max(len,now+cnt),最后再跑一次直径取较大值加到答案中即可。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll n,t;
struct node{
ll to,w;
};
vector<node>v[100040];
ll dep[100040];
bool vis[100040];
int root,root2;
ll sum=0;
ll ans=0;
ll res=0;
ll dp1[100040];
ll dp2[100040];
void dfs1(int x,int pre){
if(dep[x]>dep[root])root=x;
for(int i=0;i<v[x].size();i++){
if(v[x][i].to==pre)continue;
dep[v[x][i].to]=dep[x]+v[x][i].w;
dfs1(v[x][i].to,x);
}
}
void dfs2(int x){
vis[x]=1;res++;
for(int i=0;i<v[x].size();i++){
if(dep[x]==dep[v[x][i].to]+v[x][i].w){
dfs2(v[x][i].to);
}
}
}
ll cnt=0;
ll now=0;
ll lenn=0;
void dfs4(int x,int pre,ll d){
cnt=max(cnt,d);
for(int i=0;i<v[x].size();i++){
if(v[x][i].to==pre||vis[v[x][i].to])continue;
dfs4(v[x][i].to,x,d+v[x][i].w);
}
}
int f=0;
void dfs3(int x,int pre){
cnt=0;
if(f==0&&x!=root2){
dfs4(x,0,0);
dp1[x]=max(lenn,now+cnt);
lenn=max(lenn,now+cnt);
}
if(f==1&&x!=root){
dfs4(x,0,0);
dp2[x]=max(lenn,now+cnt);
lenn=max(lenn,now+cnt);
}
for(int i=0;i<v[x].size();i++){
if(v[x][i].to==pre||vis[v[x][i].to]==0)continue;
now+=v[x][i].w;
dfs3(v[x][i].to,x);
}
}
void dfs5(int x,int pre){
if(x!=root2){
ans+=max(dp1[pre],dp2[x]);
}
for(int i=0;i<v[x].size();i++){
if(v[x][i].to==pre||vis[v[x][i].to]==0)continue;
dfs5(v[x][i].to,x);
}
}
int main(){
scanf("%lld",&t);
while(t--){
scanf("%lld",&n);
for(int i=1;i<n;i++){
ll a,b,c;
scanf("%lld%lld%lld",&a,&b,&c);
v[a].push_back({
b,c});
v[b].push_back({
a,c});
}
for(int i=1;i<=n;i++)vis[i]=0,dp1[i]=0,dp2[i]=0;
root=0;
dep[0]=0;
dep[1]=0;
dfs1(1,0);
root2=root;
dep[root]=0;
dfs1(root,0);
sum=dep[root];
ans=0;res=0;
dfs2(root);
ans=1LL*sum*(n-res);
now=0;lenn=0;
f=0;
dfs3(root2,0);
f=1;
now=0;lenn=0;
dfs3(root,0);
dfs5(root2,0);
printf("%lld\n",ans);
for(int i=1;i<=n;i++)v[i].clear();
}
return 0;
}
//K L
K - Barricade
题意:
给你 n n n个点 m m m条边的图,你需要堵住从1到 n n n的所有最短路,堵住每条边会有一个代价。求堵住最短路的最小代价。
思路:
比赛当时,想了一个有的没的DP转移,后来发现不对。
然后其实就是一个网络流裸题,作为网络流选手,没看出来是不应该的,需要自己反思。
就先把最短路扣出来,堵住这些路就是把点1和点 n n n,分成两部分,典型的最小割。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int t,n,m;
struct node{
int to,w;
};
vector<node>v[1004];
int dis1[1004],dis2[1004];
queue<int>q;
struct edge{
int to,cap,rev;
};
vector<edge>mp[1004];
int level[1004];//顶点到源点的距离标号
int iter[1004]; //当前弧,在其之前的边已经没有用了
void add(int from,int to,int cap){
mp[from].push_back({
to,cap,mp[to].size()});
mp[to].push_back({
from,0,mp[from].size()-1});
}
void bfs(int s){
memset(level,-1,sizeof(level));
queue<int>q;
level[s]=0;
q.push(s);
while(!q.empty()){
int v=q.front();q.pop();
for(int i=0;i<mp[v].size();i++){
edge &e=mp[v][i];
if(e.cap>0&&level[e.to]<0){
level[e.to]=level[v]+1;
q.push(e.to);
}
}
}
}
int dfs(int v,int t,int f){
if(v==t)return f;
for(int &i=iter[v];i<mp[v].size();i++){
edge &e=mp[v][i];
if(e.cap>0&&level[v]<level[e.to]){
int d=dfs(e.to,t,min(f,e.cap));
if(d>0){
e.cap-=d;
mp[e.to][e.rev].cap+=d;
return d;
}
}
}
return 0;
}
int max_flow(int s,int t){
int flow=0;
while(1){
bfs(s);
if(level[t]<0)return flow;
memset(iter,0,sizeof(iter));
int f;
while((f=dfs(s,t,1e9))>0)flow+=f;
}
return flow;
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int a,b,c;scanf("%d%d%d",&a,&b,&c);
if(a==b)continue;
v[a].push_back({
b,c});
v[b].push_back({
a,c});
}
for(int i=1;i<=n;i++){
dis1[i]=dis2[i]=1e9;
}
dis1[1]=0;
while(!q.empty())q.pop();
q.push(1);
while(!q.empty()){
int x=q.front();q.pop();
for(int i=0;i<v[x].size();i++){
if(dis1[v[x][i].to]>dis1[x]+1){
dis1[v[x][i].to]=dis1[x]+1;
q.push(v[x][i].to);
}
}
}
dis2[n]=0;
q.push(n);
while(!q.empty()){
int x=q.front();q.pop();
for(int i=0;i<v[x].size();i++){
if(dis2[v[x][i].to]>dis2[x]+1){
dis2[v[x][i].to]=dis2[x]+1;
q.push(v[x][i].to);
}
}
}
for(int i=1;i<=n;i++){
for(int j=0;j<v[i].size();j++){
if(dis1[i]+dis2[v[i][j].to]+1==dis1[n]){
add(i,v[i][j].to,v[i][j].w);
}
}
}
printf("%d\n",max_flow(1,n));
for(int i=1;i<=n;i++)v[i].clear(),mp[i].clear();
}
return 0;
}
//K L
L - Eighty seven
题意:
给你 n n n个数( n < = 50 n<=50 n<=50), 每次保证不取小于等于3个数的前提下,问能否取十个数使得这十个数的和为87;
思路:
暴力背包+bitset优化
代码:
#include<bits/stdc++.h>
using namespace std;
bitset<90>s[11];
int a[51],f[51][51][51];
int n;
int solve(int x,int y,int z){
for(int i=0;i<=10;i++)s[i].reset();
s[0][0]=1;
for(int i=1;i<=n;i++){
if(i==x||i==y||i==z||a[i]>87)continue;
for(int j=10;j>0;j--){
s[j]|=s[j-1]<<a[i];
}
}
return s[10][87];
}
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
for(int k=j;k<=n;k++){
f[i][j][k]=solve(i,j,k);
}
}
}
int m;
scanf("%d",&m);
while(m--){
int b[3];
scanf("%d%d%d",&b[0],&b[1],&b[2]);
sort(b,b+3);
if(f[b[0]][b[1]][b[2]])printf("Yes\n");
else printf("No\n");
}
}
}
边栏推荐
- Field queryIndexFieldnameService in xxxImpl required a single bean, but 19 were found:
- Why microservices are needed
- 第二部分 数据链路层
- Space transcriptome experiment | what factors will affect the quality of space transcriptome sequencing during the preparation of clinical tissue samples?
- 新品发布:国产单电口千兆网卡正式量产!
- Go语言函数
- [game theory complete information static game] strategic game
- 正则校验匹配[0-100]、[0-1000]之间的正整数或小数点位数限制
- 为什么100G网络传输要使用iWARP、RoCE v2、NVMe-oF等协议
- Frequency domain filter
猜你喜欢
![[file upload vulnerability 04] server side mime detection and bypass experiment (based on upload-labs-2 shooting range)](/img/b8/521ca4bb8931afab9a3a4d0b015125.jpg)
[file upload vulnerability 04] server side mime detection and bypass experiment (based on upload-labs-2 shooting range)

Explanation of each column output by explain statement

Docker installing MySQL

使用 float 创建一个网页页眉、页脚、左边的内容和主要内容。

Release of version 5.6 of rainbow, add multiple installation methods, and optimize the topology operation experience

In idea, run the yarn command to show that the file cannot be loaded because running scripts is disabled on this system

New product release: domestic single port Gigabit network card is officially mass produced!

Deriving Kalman filter from probability theory

Application scenario: wide application of Poe network card in NDI technology for live broadcast program production

Teach you how to use win7 system to quickly build your own website
随机推荐
Part II data link layer
The gateway starts other microservices first. When the gateway is started, the gateway cannot be started and there is no exception log; Start the gateway first, and all services can be started normall
产品资讯|PoE网卡家族集体亮相,机器视觉完美搭档!
Deriving Kalman filter from probability theory
MySQL add adds multiple new fields and specifies the field location
UML系列文章(29)体系结构建模---模式和框架
【数据可视化】Apache Superset 1.2.0教程 (三)—— 图表功能详解
频域滤波器
php pcntl_fork 创建多个子进程解析
新品发布:LR-LINK联瑞推出首款25G OCP 3.0 网卡
SQL的语法
BCC tool tool usage
12 golden rules of growth
[game theory complete information static game] strategic game
【生活思考】文字与语音
Product information | Poe network card family makes a collective appearance, the perfect partner of machine vision!
Cuckoo Hash
Compilation process of program
Docker installing MySQL
Website online customer service system Gofly source code development log - 2 Develop command line applications