模拟70 考试总结

为啥根本签不上到啊

考试经过

开题T1不太会基础dp,耗了一段时间,旁边JYF20min开T2委实吓不轻,最终决定打暴力
T2目测神题先过,先写了T4的暴力,发现可以小优化一下就写了虽然依旧是暴力,T340分模拟很香也就写了,认为比较满
已经11点多看T2,写了个假贪心然后试图胡正解,发现失败了就去检查文件了
18+19+40+60=137 貌似T4的暴力还挺优秀?
T3没想到倍增,被一车人碾压,枯了

T1.暴雨

\(f[i][j][p][0/1]\)表示当前考虑前\(i\)个,最大值为\(j\)且保证后面有高度至少为\(j\)的,铲了\(p\)个,体积为偶数/奇数的方案
设下一个高度为\(a_{i+1}\),分情况讨论
\(j>=a_{i+1}\)\(f[i][j][p][op]\)有转移
\(f[i+1][j][p+1][op\oplus(j\land1)]\)把下一个铲掉
\(f[i+1][j][p][op\oplus((j-a_{i+1})\land1)]\)下一个留下
反之当\(j<a_{i+1}\)时,\(f[i][j][p][op]\)有转移
\(f[i+1][j][p+1][op\oplus(j\land1)]\)把下一个铲掉
\(f[i+1][a_{i+1}][p][op]\)下一个留下,最大值改变,体积不变
这里的第二维取值不超过\(k\),需要预处理用map映射
转移时下标要用对应map里的,不能还按照原来的
然后枚举最大值所在的位置合并,枚举两边选择的\(j\),\(p\),合并复杂度\(k^4\)

#include <bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
const int N=25050,K=30;
set <int> s1,s2;
map<int,int> mp1[N],mp2[N];
int f[N][K][K][2],g[N][K][K][2];
int rk1[N][K],rk2[N][K],tot1[N],tot2[N];
int a[N],id[N],n,k;
signed main()
{
	freopen("rain.in","r",stdin);
	freopen("rain.out","w",stdout);
	cin>>n>>k;
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	s1.insert(0);
	for(int i=1;i<=n;i++)
	{
		s1.insert(a[i]);auto ga=--s1.end();
		int num=0;tot1[i]=1;
		while(tot1[i]<k+1)
		{
			tot1[i]++;
			if(ga==s1.begin())break;ga--;	
		}
		while(1)
		{
			int p=*ga;
			if(mp1[i].find(p)==mp1[i].end())mp1[i].insert(make_pair(p,++num)),rk1[i][num]=p;
			if(ga==--s1.end())break;ga++;
		}
	}
	f[0][1][0][0]=1;tot1[0]=1;
	for(int i=0;i<n;i++)
	 for(int j=1;j<=tot1[i];j++)
	  for(int p=0;p<=k;p++)
	   for(int op=0;op<=1;op++)
	   {
	   	if(!f[i][j][p][op])continue;
	   	int jj=rk1[i][j],pp=mp1[i+1][jj];
	   	if(a[i+1]<=jj)
	   	{	
				f[i+1][pp][p+1][op^(jj&1)]=(1ll*f[i+1][pp][p+1][op^(jj&1)]+f[i][j][p][op])%mod;
				f[i+1][pp][p][op^((jj-a[i+1])&1)]=(1ll*f[i+1][pp][p][op^((jj-a[i+1])&1)]+f[i][j][p][op])%mod;
	   	}
	   	else
	   	{
	   		int hh=mp1[i+1][a[i+1]];
	   		f[i+1][pp][p+1][op^(jj&1)]=(1ll*f[i+1][pp][p+1][op^(jj&1)]+f[i][j][p][op])%mod;
	   		f[i+1][mp1[i+1][a[i+1]]][p][op]=(1ll*f[i+1][mp1[i+1][a[i+1]]][p][op]+f[i][j][p][op])%mod;
			}
		}
	s2.insert(0);
	for(int i=n;i>=1;i--)
	{
		s2.insert(a[i]);auto ga=--s2.end();
		int num=0;tot2[i]=1;
		while(tot2[i]<k+1)
		{
			tot2[i]++;
			if(ga==s2.begin())break;ga--;
		}
		while(1)
		{
			int p=*ga;
			if(mp2[i].find(p)==mp2[i].end())mp2[i].insert(make_pair(p,++num)),rk2[i][num]=p;
			if(ga==--s2.end())break;ga++;
		}
	}
	g[n+1][1][0][0]=1;tot2[n+1]=1;
	for(int i=n+1;i>=1;i--)
	 for(int j=1;j<=tot2[i];j++)
	  for(int p=0;p<=k;p++)
	   for(int op=0;op<=1;op++)
	   {	
	   	if(!g[i][j][p][op])continue;
	   	int jj=rk2[i][j],pp=mp2[i-1][jj];
	   	if(a[i-1]<=jj)
	   	{
	   		g[i-1][pp][p+1][op^(jj&1)]=(1ll*g[i-1][pp][p+1][op^(jj&1)]+g[i][j][p][op])%mod;
	   		g[i-1][pp][p][op^((jj-a[i-1])&1)]=(1ll*g[i-1][pp][p][op^((jj-a[i-1])&1)]+g[i][j][p][op])%mod;
	   	}	
	   	else
	   	{
	   		g[i-1][pp][p+1][op^(jj&1)]=(1ll*g[i-1][pp][p+1][op^(jj&1)]+g[i][j][p][op])%mod;
	   		g[i-1][mp2[i-1][a[i-1]]][p][op]=(1ll*g[i-1][mp2[i-1][a[i-1]]][p][op]+g[i][j][p][op])%mod;
			}
		}	
	for(int i=1;i<=n;i++)id[i]=a[i];
	nth_element(id+1,id+(n-k)+1,id+n+1);
	int mi=id[n-k],ans=0;
	for(int i=1;i<=n;i++)
	{
		if(a[i]<mi)continue;
		for(int j1=1;j1<=tot1[i-1]&&rk1[i-1][j1]<=a[i];j1++)
		 for(int j2=1;j2<=tot2[i+1]&&rk2[i+1][j2]<a[i];j2++)
		  for(int p=0;p<=k;p++)for(int op=0;op<=1;op++)
		    ans=(1ll*ans+1ll*f[i-1][j1][p][op]*g[i+1][j2][k-p][op]%mod)%mod;
	}
	cout<<ans<<endl;
	return 0;
}

T2.AVL

贪心,细节多,咕
大佬的链接博客

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=500050;
int n,k,root;
int son[N][2],d[N],md[N];
int f[N],w[N],h[N];
bool ans[N];int p[35];
void dfs(int x)
{
	md[x]=d[x];
	if(son[x][0])d[son[x][0]]=d[x]+1,dfs(son[x][0]),md[x]=max(md[x],md[son[x][0]]);
	if(son[x][1])d[son[x][1]]=d[x]+1,dfs(son[x][1]),md[x]=max(md[x],md[son[x][1]]);
}
inline bool check(int x)
{
	int sum=0,ga=max(d[x],h[x]);
	while(x)
	{		
		if(!ans[x])sum++;
		ga=max(ga,h[x]);
		if(x<f[x]&&ans[son[f[x]][1]]==0)
		  sum+=p[max(ga-1,w[son[f[x]][1]])-d[f[x]]];
		x=f[x];
	}
	if(sum<=k)return 1;
	else return 0;
}
void gan(int x)
{
	h[x]=max(d[x],h[x]);int ga=h[x];
	while(x)
	{
		h[x]=max(h[x],ga);
		if(!ans[x])ans[x]=1,k--;
		if(x<f[x]&&son[f[x]][1]&&ans[son[f[x]][1]]==0)
		  w[son[f[x]][1]]=max(w[son[f[x]][1]],h[x]-1);
		x=f[x];
	}
}
void dfss(int x)
{	
	if(check(x))gan(x);
	if(son[x][0]&&son[x][1])
	{
		if(md[son[x][0]]<w[x])w[son[x][0]]=max(w[son[x][0]],w[x]-1),w[son[x][1]]=max(w[son[x][1]],w[x]);
		else w[son[x][0]]=max(w[son[x][0]],w[x]),w[son[x][1]]=max(w[son[x][1]],w[x]-1);
		dfss(son[x][0]);dfss(son[x][1]);
	}
	else if(son[x][0])
	{
		w[son[x][0]]=max(w[son[x][0]],w[x]);
		dfss(son[x][0]);		
	}
	else if(son[x][1])
	{
		w[son[x][1]]=max(w[son[x][1]],w[x]);
		dfss(son[x][1]);
	}
}
signed main()
{
	freopen("avl.in","r",stdin);
	freopen("avl.out","w",stdout);
	cin>>n>>k;
	p[0]=0;p[1]=1;
	for(int i=2;i<=30;i++)p[i]=p[i-1]+p[i-2]+1;
	for(int i=1;i<=n;i++)
	{
		int fa;scanf("%lld",&fa);
		if(fa!=-1)
		{
			if(!son[fa][0])son[fa][0]=i;
			else if(i>son[fa][0])son[fa][1]=i;
			else son[fa][1]=son[fa][0],son[fa][0]=i;
			f[i]=fa;
		}
		else root=i;
	}	
	d[root]=1;dfs(root);dfss(root);
	for(int i=1;i<=n;i++)
	{
		if(ans[i])putchar('1');
		else putchar('0');		
	}
	return 0;
}

预处理的深度要保证够500000个节点

T3.挖掘机

这文件名什么鬼啊
显然行独立,每次贪心从第一个X开始一定不劣,考虑倍增
先预处理出每个点前、后第一个X在哪里,然后倍增预处理出跳\(2^k\)能到哪里
然后每次就\(log\)计算就好了,判一下根本不用跳的

#include <bits/stdc++.h>
using namespace std;
const int N=100050;
char a[14][N];
inline int read()
{
	char ch=getchar();int x=0;
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return x;
}
int f[14][N][20],from[14][N],to[14][N],bit[20];
signed main()
{
	freopen("blueshit.in","r",stdin);
	freopen("blueshit.out","w",stdout);
	int h,w,k,q;cin>>h>>w>>k>>q;
	for(int i=1;i<=h;i++)scanf("%s",a[i]+1);
	bit[0]=1;for(int i=1;i<20;i++)bit[i]=bit[i-1]*2;
	for(int i=1;i<=h;i++)
	{
		for(int j=1;j<=w;j++)if(a[i][j]=='X')
		{
			to[i][j]=from[i][j]=j;
			for(int p=j-1;p>=1;p--)
			{
				if(a[i][p]=='X')break;
				to[i][p]=j;
			}
			for(int p=j+1;p<=w;p++)
			{
				if(a[i][p]=='X')break;
				from[i][p]=j;
			}
		}
		for(int j=w;j>=1;j--)
		{
			int t=(double)log(w-j+1)/log(2)+1;
			f[i][j][0]=to[i][j+k];
			for(int p=1;p<=t;p++)
			 f[i][j][p]=f[i][f[i][j][p-1]][p-1];
		}
	}
	for(int i=1;i<=q;i++)
	{
		int d=read(),l=read(),r=read();
		int ans=0;
		for(int j=1;j<=d;j++)
		{
			int ed=from[j][r],x=to[j][l];if(ed<l)continue;
			if(ed-x+1<k){ans++;continue;}
			int t=(double)log(ed-x+1)/log(2)+1;
			for(int p=t;p>=0;p--)
			{
				if(f[j][x][p]>ed)continue;
				if(!f[j][x][p])continue;
				x=f[j][x][p];ans+=bit[p];
			}
			ans++;
		}
		printf("%d\n",ans);
	}
	return 0;
}

T4.游戏

后缀数组+线段树维护矩阵乘法,听名字就不友好,咕

考试总结

这一场暴力比较满,主要是心态调整的比较快
打暴力之前先把学过的东西想一遍,看有没有什么能套的没有,一直签不上到可不太行

posted @ 2021-10-08 06:36  D'A'T  阅读(52)  评论(0)    收藏  举报