初三奥赛模拟测试3

初三奥赛模拟测试3

\(T1'\) 糖果 \(100pts\)

\(T2'\) 魔法仪式 \(0pts\)

\(T3'\) 独特的数组 \(0pts\)

\(T4'\) 约会 \(0pts\)

\(T1\) 网格图 \(0pts\)

  • 正解
    • 先处理出所有连通块及其大小,并记录每个 . 在哪个连通块中。

    • 考虑枚举 \(k \times k\) 的正方形,将正方形内的所有 . ,在其对应的连通块大小中扣除,然后再枚举正方形外圈的连通块,求它们的大小之和,取 \(\max\) 即可。

    • 记其右下角为 \((x,y)\) 。考虑右下角由 \((x,y-1)\) 变成 \((x,y)\) 时, \((i,y-k+1-1)\) 无法对答案产生贡献, \((i,y)\) 会对答案产生贡献,故可以只枚举这两列从而优化时间复制度。

    • 注意及时消除影响。

      点击查看代码
      int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1},num[250010],pos[510][510],vis[510][510],viss[250010];
      char c[510][510];
      void dfs(int x,int y,int n,int id)
      {
      	vis[x][y]=1;
      	num[id]++;
      	pos[x][y]=id;
      	for(int i=0;i<=3;i++)
      	{
      		if(1<=x+dx[i]&&x+dx[i]<=n&&1<=y+dy[i]&&y+dy[i]<=n&&vis[x+dx[i]][y+dy[i]]==0)
      		{
      			dfs(x+dx[i],y+dy[i],n,id);
      		}
      	}
      }
      int main()
      {
      	int n,m,id=0,sum,ans=0,i,j,k,h;
      	cin>>n>>m;
      	for(i=1;i<=n;i++)
      	{
      		for(j=1;j<=n;j++)
      		{
      			cin>>c[i][j];
      			vis[i][j]=(c[i][j]=='X');
      		}
      	}
      	for(i=1;i<=n;i++)
      	{
      		for(j=1;j<=n;j++)
      		{
      			if(vis[i][j]==0)
      			{
      				id++;
      				dfs(i,j,n,id);
      			}
      		}
      	}
      	for(i=m;i<=n;i++)
      	{
      		for(j=m;j<=n;j++)
      		{
      			if(j==m)
      			{   
      				for(k=i-m+1;k<=i;k++)
      				{
      					for(h=j-m+1;h<=j;h++)
      					{
      						if(c[k][h]=='.')
      						{
      							num[pos[k][h]]--;
      						}
      					}
      				}
      			}
      			else
      			{
      				for(k=i-m+1;k<=i;k++)
      				{
      					h=j-m+1-1;
      					if(c[k][h]=='.')
      					{
      						num[pos[k][h]]++;
      					}
      				}
      				for(k=i-m+1;k<=i;k++)
      				{
      					h=j;
      					if(c[k][h]=='.')
      					{
      						num[pos[k][h]]--;
      					}
      				}
      			}
      			sum=0;
      			if(1<=i-m+1-1)
      			{
      				for(k=j-m+1;k<=j;k++)
      				{
      					sum+=(viss[pos[i-m+1-1][k]]==0)*num[pos[i-m+1-1][k]];
      					viss[pos[i-m+1-1][k]]=1;
      				}
      			}
      			if(i+1<=n)
      			{
      				for(k=j-m+1;k<=j;k++)
      				{
      					sum+=(viss[pos[i+1][k]]==0)*num[pos[i+1][k]];
      					viss[pos[i+1][k]]=1;
      				}
      			}
      			if(1<=j-m+1-1)
      			{
      				for(k=i-m+1;k<=i;k++)
      				{
      					sum+=(viss[pos[k][j-m+1-1]]==0)*num[pos[k][j-m+1-1]];
      					viss[pos[k][j-m+1-1]]=1;
      				}
      			}
      			if(j+1<=n)
      			{
      				for(k=i-m+1;k<=i;k++)
      				{
      					sum+=(viss[pos[k][j+1]]==0)*num[pos[k][j+1]];
      					viss[pos[k][j+1]]=1;
      				}
      			}
      			if(1<=i-m+1-1)
      			{
      				for(k=j-m+1;k<=j;k++)
      				{
      					viss[pos[i-m+1-1][k]]=0;
      				}
      			}
      			if(i+1<=n)
      			{
      				for(k=j-m+1;k<=j;k++)
      				{
      					viss[pos[i+1][k]]=0;
      				}
      			}
      			if(1<=j-m+1-1)
      			{
      				for(k=i-m+1;k<=i;k++)
      				{
      					viss[pos[k][j-m+1-1]]=0;
      				}
      			}
      			if(j+1<=n)
      			{
      				for(k=i-m+1;k<=i;k++)
      				{
      					viss[pos[k][j+1]]=0;
      				}
      			}
      			if(j==n)
      			{
      				for(k=i-m+1;k<=i;k++)
      				{
      					for(h=j-m+1;h<=j;h++)
      					{
      						if(c[k][h]=='.')
      						{
      							num[pos[k][h]]++;
      						}
      					}
      				}
      			}
      			ans=max(ans,sum+m*m);
      		}
      	}
      	cout<<ans<<endl;
      	return 0;
      }
      

\(T2\) 序列问题 \(0pts\)

  • 正解
    • \(f_{i}\) 表示处理到第 \(i\) 个数且处理后的序列以 \(a_{i}\) 结尾,且 \(a_{i}\) 产生了贡献时的最大值,状态转移方程为 \(f_{i}= \max\limits_{j=1}^{i-1} \{ [a_{j}<a_{i} \And \And a_{i}-a_{j} \le i-j] \times (f_{j}+1) \}= \max\limits_{j=1}^{n} \{ [a_{j}<a_{i} \And \And j-a_{j} \le i-a_{i}] \times (f_{j}+1) \}\)

    • 维护 \(i-a_{i}\) 的最长不降子序列即可。

      点击查看代码
      struct node
      {
          int x,id;
      }a[500010];
      bool cmp(node a,node b)
      {
          return (a.x==b.x)?(a.id>b.id):(a.x<b.x);//注意当x相等时,id要降序排序
      }
      int f[500010];
      int main()
      {
          freopen("sequence.in","r",stdin);
          freopen("sequence.out","w",stdout);
          int n,ans=0,i;
          cin>>n;
          for(i=1;i<=n;i++)
          {
              cin>>a[i].x;
              a[i].id=i;
          }
          sort(a+1,a+1+n,cmp);
          for(i=1;i<=n;i++)
          {
              if(a[i].id-a[i].x>=0)
              {
                  if(a[i].id-a[i].x>=f[ans])
                  {   
                      ans++;
                      f[ans]=a[i].id-a[i].x;
                  }
                  else
                  {
                      f[upper_bound(f+1,f+1+ans,a[i].id-a[i].x)-f]=a[i].id-a[i].x;
                  }
              }
          }
          cout<<ans<<endl;
          fclose(stdin);
          fclose(stdout);
          return 0;
      }
      

\(T3\) 置换 \(0pts\)

\(T4\) 同桌的你 \(0pts\)

总结

后记

posted @ 2024-03-26 18:05  hzoi_Shadow  阅读(43)  评论(2编辑  收藏  举报
扩大
缩小