2019.6.26总结

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));
	}
}

总结

今天比赛不够专注,下次要继续努力,在比赛时,要合理安排时间,不要在一道题上面卡死。

对于不够熟练的知识点,要多做相关题目。

(中考加油!)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值