模拟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.游戏
后缀数组+线段树维护矩阵乘法,听名字就不友好,咕
考试总结
这一场暴力比较满,主要是心态调整的比较快
打暴力之前先把学过的东西想一遍,看有没有什么能套的没有,一直签不上到可不太行

浙公网安备 33010602011771号