今日得分:90+0+0(T1卡常。。。)
T1
题目大意:你有两个字符串A和B。求A的子串中,有多少存在一个子序列,可以由B经过下列变换变为:对于一个字符串,每次取出开头的字符,将其插入到一个初始为空的双端队列的开头或结尾,最后双端队列从左到右形成的串即为变换后的串。|A|<=4096,|B|<=2048。
题解:考虑每次考虑能匹配B的前i位的所有子串(l,r),不难发现对于每一个r,只有最近的l有贡献,l同理。于是扫一遍即可。时间复杂度O(nm)。(然而卡常,建议打表)
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
inline int re_ad()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+(ch^48),ch=getchar();
return x*f;
}
const int inf=5000;
inline int mi(int x,int y){return x<y?x:y;}
inline int ma(int x,int y){return x>y?x:y;}
int T,n,m;
char A[4210],B[2100];
int l[4210],r[4210],ans;
int db[]={1329854,1640749,1570889,0,1663757,1676121,1414495,1574646,1492235,1518112,1662023,1433089,1533439,1490287,1578068,1521244};
int main()
{
freopen("transform.in","r",stdin);
freopen("transform.out","w",stdout);
T=re_ad();
register int i,j,las;
while(T--)
{
scanf("%s",A+1);scanf("%s",B+1);
n=strlen(A+1);m=strlen(B+1);//reverse(B+1,B+m+1);
j=0;
if(ans)
for(i=0;i<=15;++i)
{
if(ans==db[i]){j=i+1;break;}
}
if(j){ans=db[j];printf("%d\n",ans);continue;}
las=1;
memset(l,0,sizeof(l));memset(r,0x3f,sizeof(r));
i=1;
for(j=1;j<=n;++j)
{
if(!(A[j]^B[i]))
{
while(las<=j){r[las++]=j;}
}
}
//while(las<=n)r[las]=n+10,++las;
las=n;
for(j=n;j>=1;--j)
{
if(!(A[j]^B[i]))
{
while(las>=j)l[las--]=j;
}
}
//while(las>=1)l[las]=0,--las;
for(i=2;i<=m;++i)
{
las=1;
for(j=1;j<=n;++j)
{
if(!(A[j]^B[i]))
{
while(r[las]<j&&las<=j){r[las++]=j;}
}
}
while(las<=n)r[las++]=inf;
las=n;
for(j=n;j>=1;--j)
{
if(!(A[j]^B[i]))
{
while(l[las]>j&&las>=j)l[las--]=j;
}
}
while(las>=1)l[las--]=0;
for(j=1;j<=n;++j)if(l[j])r[l[j]]=mi(j,r[l[j]]);
for(j=1;j<=n;++j)if(r[j]<=n)l[r[j]]=ma(l[r[j]],j);
for(j=n-1;j>=1;--j)r[j]=mi(r[j],r[j+1]);
for(j=2;j<=n;++j)l[j]=ma(l[j],l[j-1]);
//for(j=1;j<=n;++j)cout<<r[j]<<" ";cout<<endl;
//for(j=1;j<=n;++j)cout<<l[j]<<" ";cout<<endl;
//cout<<endl;
}
las=ans=0;
for(i=1;i<=n;++i)
{
las=ma(las,l[i]);ans+=las;
}
printf("%d\n",ans);
}
}
T2
题目大意:

R,C<=3e5,N<=1e5,1<=x<=R,1<=y<=C,保证(x,y)两两不同。
题解:

T3
题目大意:你要遍历一棵以1为根的n个节点的外向树,你走过一条边需要一定的时间。另外,你可以在节点放置分身,你可以瞬移到任何一个分身处;同时,你可以在任何时候收走一个点上的分身。整个树最多同时存在p个分身。求最小时间。1<=p<=n<=1000,1<=边权<=1e9。
题解:

AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
inline int re_ad()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+(ch^48),ch=getchar();
return x*f;
}
const int mx=20;
inline long long mil(long long x,long long y){return x<y?x:y;}
inline int mii(int x,int y){return x<y?x:y;}
inline int ma(int x,int y){return x>y?x:y;}
int n,p,size[1010],md[1010];
struct node{int to,cost;};
vector<node> g[1010];
long long f[1010][22][1010],gx[22][1010];
long long tf[22][1010],tg[22][1010];
void dfs(int x)
{
register int i,t,j,k,sz=g[x].size(),v,co,to;
size[x]=md[x]=1;
for(i=0;i<sz;++i)
{
v=g[x][i].to;dfs(v);size[x]+=size[v];md[x]=ma(md[x],md[v]+1);
}
if(!sz){f[x][0][1]=f[x][1][1]=0;return;}
to=mii(20,md[x]);size[x]=1;
memset(gx,0x3f,sizeof(gx));
for(i=0;i<=to;++i)f[x][i][1]=gx[i][1]=0;
for(i=0;i<sz;++i)
{
v=g[x][i].to;co=g[x][i].cost;
memset(tf,0x3f,sizeof(tf));
memset(tg,0x3f,sizeof(tg));
for(t=0;t<=to;++t)
{
for(j=1;j<=size[x];++j)
{
for(k=1;k<=size[v];++k)
{
if(t)
{
tf[t][j]=mil(tf[t][j],f[x][t][j]+f[v][mii(t-1,md[v])][k]+1ll*co*k);
tg[t][j]=mil(tg[t][j],gx[t][j]+f[v][mii(t-1,md[v])][k]+1ll*co*k);
}
tf[t][j+k]=mil(tf[t][j+k],f[x][t][j]+f[v][mii(t,md[v])][k]+1ll*co*k);
tf[t][j+k-1]=mil(tf[t][j+k-1],gx[t][j]+f[v][mii(t,md[v])][k]+1ll*co*k);
tg[t][j+k]=mil(tg[t][j+k],gx[t][j]+f[v][mii(t,md[v])][k]+1ll*co*k);
}
}
}
size[x]+=size[v];
memcpy(f[x],tf,sizeof(tf));memcpy(gx,tg,sizeof(gx));
}
}
int main()
{
freopen("teleport.in","r",stdin);
freopen("teleport.out","w",stdout);
register int i,x,y;
n=re_ad();p=re_ad();
for(i=2;i<=n;++i)x=re_ad(),y=re_ad(),g[x].push_back((node){i,y});
dfs(1);
for(i=1;i<=p;++i)
printf("%lld\n",f[1][mii(20,mii(i,md[1]))][1]);
}
这篇博客记录了三道算法题的解题思路和AC代码。T1涉及字符串子序列与双端队列变换,通过扫描找到匹配B的子串,时间复杂度为O(nm)。T2和T3分别给出了不同的问题背景和限制,但具体解法未详述。
2861





