模拟11 考试总结

比较。。正常吧

考试经过

一点进去发现这次给了一大堆样例,挺开心
T1看上去是构造题,先想到了取模然后就不会了,看着第三个样例产生了疑惑,就一个数为啥能全出来呢?手玩的过程中想到了gcd,然后惊喜发现输出的就是答案,然后就切了,顺便被绿一次(笑)
T2一眼看出根据拓扑序建图dp,一发离散化之后40带走,然后就不会优化了,想到了单调队列,根本不敢写,然后开T3
T3先冲暴力20,然后推第一个特殊性质,死活推不出来,剩半小时推性质2,发现几乎是白送。。。然后冲上特判,40拿走,坐等出分。。。
估分100+40+40=180,真就一分不差
rank4,%%%上面的战神,赵sir,付队,战神250太可怕了吧……
JYFT2出了半正解有了80高分,土哥似乎T1没有满就仨并列
看了看2018学长,一群上200的。。。

\[菜 我 还 是 \]

T1.math

我的做法其实是假的
我是对每个数分别对k取模,然后求所有数和\(gcd(a_i,k)\)的最小值就是公差,A了,但战神给了这么一个数据:
3 6
2 3
答案是0到5,而我出来公差是2……
正解使用裴蜀定理image
说白了就是求整个序列的gcd,记得最后再和k求一次gcd

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=500500;
int a[N];vector <int> an;
inline int gcd(int x,int y)
{
	if(y==0)return x;
	else return gcd(y,x%y);
}
signed main()
{
	int n,k;cin>>n>>k;
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
	for(int i=1;i<=n;i++)a[i]%=k;
	int p=k;
        for(int i=1;i<=n;i++)if(a[i])p=gcd(p,a[i]);
        int ans=0;
        for(int i=0;i<k;i+=p)an.push_back(i),ans++;
        cout<<ans<<endl; 
	for(int i=0;i<an.size();i++)printf("%lld ",an[i]);
	return 0;    
}

我骗了100分,我其实只是一个80的菜鸡。。。
放弃了绿框,因为要相信真理

T2.biology

可以根据拓扑序进行dp,复杂度$n_4&,40分
观察这个dp很容易有状态转移方程

\[f_{i,j}=max(f_{i',j'}+b_{i',j'}+|i-i'|+|j-j'|),a_{i,j}=a_{i',j'}+1 \]

由于这个东西是矩阵,所以他的复杂度下界应该不会少于\(n_2\),我们考虑优化
发现这个max比较耗时间,我们希望把他转化到至少\(log\)级别才行
考虑将绝对值拆开,在左上,左下,右上,右下四个方向上用数据结构维护最值
有关数据结构,二维,你想到了什么?显然树状数组
等等,树状数组能维护最值吗?

如果要处理区间最值问题,树状数组就无能为力了
————林厚从《高级数据结构》

书上说的没错,由于最值不满足区间可加性,所以不能求任意区间的最值,硬要求的话要额外维护\(log\)
但是,我们能求一段前缀的最值!
因为只有前缀不用做差,所以在普通代码里把加变成取max就行了
那么我们要把四个角都变成前缀,怎么办?土哥告诉我们:

将add和query函数里的循环顺序和方向变一下就行了

简直不能再妙,%%%
所以我们写出了四个树状数组,注意各个方向

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=2050;
int a[N][N],b[N][N];
int n,m;
struct node{
	int x,y,v;
}c[N*N];int tot,lsh[N*N];
inline void add(int x,int y,int v)
{
	c[++tot].x=x;c[tot].y=y;c[tot].v=v;
}
inline int lowbit(int x)
{
	return x&(-x);
}
int t1[N][N],t2[N][N],t3[N][N],t4[N][N];
//t1左上t2左下t3右上t4右下 
inline void add1(int x,int y,int v)
{
   for(int i=x;i<=n;i+=lowbit(i))
    for(int j=y;j<=m;j+=lowbit(j))
      t1[i][j]=max(t1[i][j],v);	
} 
inline int get1(int x,int y)
{
   int s=0;
   for(int i=x;i;i-=lowbit(i))
    for(int j=y;j;j-=lowbit(j))
      s=max(s,t1[i][j]);
   return s;
}
inline void add2(int x,int y,int v)
{
   for(int i=x;i<=n;i+=lowbit(i))
    for(int j=y;j;j-=lowbit(j))
      t2[i][j]=max(t2[i][j],v);
}
inline int get2(int x,int y)
{
   int s=0; 
   for(int i=x;i;i-=lowbit(i))
    for(int j=y;j<=m;j+=lowbit(j))
     s=max(s,t2[i][j]);
   return s; 
}
inline void add3(int x,int y,int v)
{
   for(int i=x;i;i-=lowbit(i))
    for(int j=y;j<=m;j+=lowbit(j))
     t3[i][j]=max(t3[i][j],v);
}
inline int get3(int x,int y)
{
  int s=0;
  for(int i=x;i<=n;i+=lowbit(i))
    for(int j=y;j;j-=lowbit(j))
     s=max(s,t3[i][j]);
  return s;
}
inline void add4(int x,int y,int v)
{
  for(int i=x;i;i-=lowbit(i))
    for(int j=y;j;j-=lowbit(j))
     t4[i][j]=max(t4[i][j],v);
}
inline int get4(int x,int y)
{
  int s=0;
  for(int i=x;i<=n;i+=lowbit(i))
    for(int j=y;j<=m;j+=lowbit(j))
     s=max(s,t4[i][j]); 
  return s;
}
bool cmp(node x,node y)
{
  return x.v<y.v;
}
queue <node> q;
inline void doit()
{
   while(!q.empty())
   {
  	int x=q.front().x,y=q.front().y,v=q.front().v;
	add1(x,y,v-x-y);add2(x,y,v-x+y);
	add3(x,y,v+x-y);add4(x,y,v+x+y);
	q.pop();
   }
}
signed main()
{
  cin>>n>>m;
  for(int i=1;i<=n;i++)
  for(int j=1;j<=m;j++)
  scanf("%lld",&a[i][j]);
  for(int i=1;i<=n;i++)
   for(int j=1;j<=m;j++)
    scanf("%lld",&b[i][j]); 
  for(int i=1;i<=n;i++)
   for(int j=1;j<=m;j++)
    add(i,j,a[i][j]);
  for(int i=1;i<=tot;i++)lsh[i]=c[i].v;
  sort(lsh+1,lsh+tot+1);
  int cnt=unique(lsh,lsh+tot+1)-lsh-1;
  for(int i=1;i<=tot;i++)
   c[i].v=lower_bound(lsh,lsh+cnt+1,c[i].v)-lsh;
  sort(c+1,c+1+tot,cmp);
  int ans=0;
  for(int i=1;i<=tot;i++)
  {
  	if(!c[i].v)continue;
    	if(c[i].v!=c[i-1].v)doit();
    	node p;p.x=c[i].x,p.y=c[i].y;
    	int xx=c[i].x,yy=c[i].y;
    	if(c[i].v==1)
    	{
    		p.v=b[xx][yy];ans=max(ans,p.v);
    		q.push(p);continue;
		}
		p.v=max(max(get1(xx,yy)+xx+yy,get2(xx,yy)+xx-yy),max(get3(xx,yy)-xx+yy,get4(xx,yy)-xx-yy))+b[xx][yy];//
		ans=max(ans,p.v);
		q.push(p);
	}
	cout<<ans;
	return 0;
}  

注意拆的时候的正负要和后面的正负号相反,我标记的内行,保证距离最后是差的形式
算法复杂度\(O(nmlog_mlog_n)\),交了之后我们获得了80分的高分
继续优化!把log砍掉 !
实际上感性理解一下,最靠边的店会更优,我们根本不用树状数组,开四个变量记一下就行

#include <bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
       int x=0;char ch=getchar();
       while(ch<'0'||ch>'9'){ch=getchar();}
       while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
       return x;
}
const int N=2050;
int a[N][N],b[N][N];
int n,m;
struct node{
	int x,y,v;
}c[N*N];int tot,lsh[N*N];
inline void add(int x,int y,int v)
{
	c[++tot].x=x;c[tot].y=y;c[tot].v=v;
}
bool cmp(node x,node y)
{
	return x.v<y.v;
}
int p1,p2,p3,p4;
queue <node> q;
inline void doit()
{
	while(!q.empty())
	{
		int x=q.front().x,y=q.front().y,v=q.front().v;
		p1=max(p1,v-x-y),p2=max(p2,v-x+y);
		p3=max(p3,v+x-y),p4=max(p4,v+x+y);
		q.pop();
	}
}
signed main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	 for(int j=1;j<=m;j++)
	  a[i][j]=read(); 
	for(int i=1;i<=n;i++)
	 for(int j=1;j<=m;j++)
	  b[i][j]=read();
	for(int i=1;i<=n;i++)
	 for(int j=1;j<=m;j++)
	  add(i,j,a[i][j]);
	for(int i=1;i<=tot;i++)lsh[i]=c[i].v;
        sort(lsh+1,lsh+tot+1);
        int cnt=unique(lsh,lsh+tot+1)-lsh-1;
        for(int i=1;i<=tot;i++)
         c[i].v=lower_bound(lsh,lsh+cnt+1,c[i].v)-lsh;
        sort(c+1,c+1+tot,cmp);
        int ans=0;
        for(int i=1;i<=tot;i++)
        {
    	  if(!c[i].v)continue;
    	  if(c[i].v!=c[i-1].v)doit();
    	  node p;p.x=c[i].x,p.y=c[i].y;
    	  int xx=c[i].x,yy=c[i].y;
    	  if(c[i].v==1)
    	  {
    		p.v=b[xx][yy];ans=max(ans,p.v);
    		q.push(p);continue;
	  }
	  p.v=max(max(p1+xx+yy,p2+xx-yy),max(p3-xx+yy,p4-xx-yy))+b[xx][yy];
	  ans=max(ans,p.v);
	  q.push(p);
	}
	cout<<ans;
	return 0;
}  

注意更新的时候因为是分层转移的,所以不能一个一个更新,要批量更新

T3Eglish

暴力20不解释
第二个性质比较好骗,又有20
正解:可持久化01trie
确定是我不会的东西了

posted @ 2021-07-11 19:20  D'A'T  阅读(53)  评论(0)    收藏  举报