2019.6.26总结
比赛情况
9.1+100+0=109.1
Rank 11(比昨天多了个1)
T1
-
其实这道题考场切了…但是由于一些比较不可原谅的错误~~(诸如打了函数忘记调用之类的)~~,所以没有切掉…
-
下次一定要注意(我是不会说我因为这个调了半个小时的)!!!
-
其实这是我第一次在AC自动机上打DP(虽然中间过程不是很顺利),但是总体还是不错的,至少推出来了DP方程。
-
设f[i][j]表示当前串到了第i位,在Trie上的第j个点(编号为j),由此我们可以预处理出数组s[i][j]表示当在Trie上第i个点(编号为i)时,下一个填的字符是j时应该跳到Trie上的哪一个点。
-
进而可以得到方程f[i][s[j][k]]+=f[i][j]。
-
由于我们是要求不匹配的串,所以我们在每个串的结尾所在Trie的节点打上标记,DP时不能去到打了标记的点。
code
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#define N 30005
#define ll long long
using namespace std;
//For 2000 yuan
int n,m,p,w[N],son[N][50],fail[N],g[N],tot;
char s[305],st[305];
struct big
{
int a[105],len;
int put(int x){len=1,a[1]=x;}
big add(big b)
{
big ans;
memset(ans.a,0,sizeof ans.a),ans.len=max(len,b.len);
for (int i=1;i<=ans.len;i++)
ans.a[i]+=a[i]+b.a[i],ans.a[i+1]+=ans.a[i]/10,ans.a[i]%=10;
ans.len+=(ans.a[ans.len+1]>0),len=ans.len;
for (int i=1;i<=ans.len;i++)
a[i]=ans.a[i];
}
int output()
{
printf("%d",a[len]);
for (int i=len-1;i;i--)
printf("%d",a[i]);
}
}f[105][105],ans;
int trie_build()
{
int now=0,len=strlen(st);
for (int i=0;i<len;i++)
{
int p=g[st[i]];
if (!son[now][p])
son[now][p]=++tot;
now=son[now][p];
}
w[now]=1;
}
int AC_build()
{
int q[30001],h=0,t=0;
for (int i=1;i<=n;i++)
if (son[0][i])
q[t++]=son[0][i],fail[son[0][i]]=0;
while (h!=t)
{
int head=q[h++];
w[head]|=w[fail[head]];
for (int i=1;i<=n;i++)
if (son[head][i])
q[t++]=son[head][i],fail[son[head][i]]=son[fail[head]][i];
else
son[head][i]=son[fail[head]][i];
}
}
int main()
{
scanf("%d%d%d",&n,&m,&p);
scanf("%s",s);
for (int i=0;i<n;i++)
g[s[i]]=i+1;
for (int i=1;i<=p;i++)
scanf("%s",st),trie_build();
AC_build();
for (int i=0;i<=m;i++)
for (int j=0;j<=tot+1;j++)
f[i][j].put(0);
f[0][0].put(1);
for (int i=0;i<m;i++)
for (int j=0;j<=tot;j++)
for (int q=1;q<=n;q++)
if (!w[son[j][q]])
f[i+1][son[j][q]].add(f[i][j]);
ans.put(0);
for (int i=0;i<=tot;i++)
ans.add(f[m][i]);
ans.output();
}
T2
- 这道题的数据范围确实很小…
(数据也很水) - 唯一一道考场切了的题。
- 其实呢,并查集的方法,很好想,很好打,但时间却很卡。
- 先将边权离散化,就可以得到m个值。
- 再枚举最小值,二分出能让起点和终点连通的最小上界,更新答案即可。
- 对于判断连通性,直接将所有点放入并查集即可。
- 这题真的很容易想…
code
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#define N 6005
#define ll long long
using namespace std;
//For 2000 yuan
int n,m,S,T,p[N],tot,ans=1e9,f[N];
struct edge{int x,y,z;}a[N];
bool cmp(edge x,edge y){return x.z<y.z;}
int get(int x){return (f[x]==x)?x:f[x]=get(f[x]);}
int pd(int l,int r)
{
for (int i=1;i<=n;i++)
f[i]=i;
for (int i=l,x,y;i<=r;i++)
{
x=get(a[i].x),y=get(a[i].y);
if (x!=y)
f[x]=y;
f[x]=y;
}
for (int i=r+1,x,y;i<=tot&&a[i].z==a[r].z;i++)
{
x=get(a[i].x),y=get(a[i].y);
if (x!=y)
f[x]=y;
}
f[S]=get(f[S]),f[T]=get(f[T]);
return f[S]==f[T];
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1,x,y,z;i<=m;i++)
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
scanf("%d%d",&S,&T),sort(a+1,a+m+1,cmp);
for (int i=1;i<=m;i++)
tot+=(a[i].z!=a[i-1].z),p[tot]=a[i].z,a[i].z=tot;
for (int i=1,l,r,mid;i<=tot;i++)
{
l=i,r=tot;
while (l<r)
mid=(l+r)/2,(pd(i,mid))?r=mid:l=mid+1;
if (!pd(i,l))
l++;
if (l<=tot&&pd(i,l))
ans=min(ans,p[l]-p[i]);
}
(ans!=1e9)?printf("%d",ans):printf("-1");
}
T3
- splay裸题,可惜好久没打了,并且时间不足。
- 正好可惜借这道题练手,找回之前很久之前打splay痛心疾首的感觉(话说我打得第一道splay的题是排序(xie)机械臂)。
- 其他的不做过多讲述,几个重要的操作要熟记…
- 不过好像除了这几个重要的操作就没有了…
- 那就没有了吧。
- splay这种东西还是要靠日复一日的不懈练习的。
code
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#define N 400005
#define ll long long
#define mid ((l+r)/2)
#define L s[x][0]
#define R s[x][1]
using namespace std;
//For 2000 yuan
int n,m;
char ch;
struct sp
{
int sum[N],ls[N],rs[N],s[N][2],a[N],root,size[N],ans[N],key[N],tot,f[N];
inline int updata(int x)
{
if (!x)
return 0;
size[x]=size[L]+size[R]+1,sum[x]=key[x]+sum[L]+sum[R];
ls[x]=max(ls[L],key[x]+sum[L]+max(0,ls[R])),rs[x]=max(rs[R],key[x]+sum[R]+max(0,rs[L]));
ans[x]=max(max(ans[L],ans[R]),key[x]+max(0,rs[L])+max(0,ls[R]));
}
inline int get(int &x,int v,int fa){x=++tot,sum[x]=ls[x]=rs[x]=ans[x]=key[x]=v,f[x]=fa,size[x]=1;}
inline int build(int &x,int l,int r,int fa)
{
if (l<=r)
get(x,a[mid],fa),build(L,l,mid-1,x),build(R,mid+1,r,x),updata(x);
}
inline int tg(){ls[0]=rs[0]=ans[0]=key[0]=-1e9,get(root,-1e9,0),get(s[root][1],-1e9,root),build(s[s[root][1]][0],1,n,s[root][1]),updata(s[root][1]),updata(root);}
inline int rotate(int x)
{
int y=f[x],z=f[y],k=(s[f[x]][1]==x),w=s[x][k^1];
s[y][k]=w,f[w]=y,s[z][(s[f[y]][1]==y)]=x,f[x]=z;
s[x][k^1]=y,f[y]=x,updata(y),updata(x);
}
inline int splay(int x,int g)
{
while (f[x]!=g)
{
int y=f[x],z=f[y];
if (z!=g)
if ((s[f[x]][1]==x)==(s[f[y]][1]==y))
rotate(y);
else
rotate(x);
rotate(x);
}
if (!g)
root=x;
}
inline int st(int y,int z)
{
int x=root;
while (size[L]+1!=y)
if (y<size[L]+1)
x=L;
else
y-=size[L]+1,x=R;
splay(x,z);
return x;
}
inline int ins(int x,int y){st(x,0),st(x+1,root),get(s[s[root][1]][0],y,s[root][1]),updata(s[root][1]),updata(root);}
inline int del(int x){st(x,0),st(x+2,root),s[s[root][1]][0]=0,updata(s[root][1]),updata(root);}
inline int replace(int a,int b)
{
int x=root;
a++;
while (size[L]+1!=a)
if (a<size[L]+1)
x=L;
else
a-=size[L]+1,x=R;
key[x]=b,splay(x,0);
}
inline int find(int x,int y)
{
st(x,0),st(y+2,root);
return ans[s[s[root][1]][0]];
}
}f;
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&f.a[i]);
f.tg();
scanf("%d",&m);
for (int tt=1,x,y;tt<=m;tt++)
{
scanf("%c",&ch);
while (ch!='I'&&ch!='D'&&ch!='R'&&ch!='Q')
scanf("%c",&ch);
if (ch=='I')
scanf("%d%d",&x,&y),f.ins(x,y);
if (ch=='D')
scanf("%d",&x),f.del(x);
if (ch=='R')
scanf("%d%d",&x,&y),f.replace(x,y);
if (ch=='Q')
scanf("%d%d",&x,&y),printf("%d\n",f.find(x,y));
}
}
总结
今天比赛不够专注,下次要继续努力,在比赛时,要合理安排时间,不要在一道题上面卡死。
对于不够熟练的知识点,要多做相关题目。