初三奥赛模拟测试1

初三奥赛模拟测试1

\(T1\) 回文 \(0pts\)

  • 正解

    • \(f_{x_{1},y_{1},x_{2},y_{2}}\) 表示从 \((1,1)\)\((x_{1},y_{1})\) 结束的回文路径条数,其中 \((x_{1},y_{1})\) 关于最终形成的回文串的回文中心的对称点为 \((x_{2},y_{2})\) 。状态转移方程为 \(f_{x_{1},y_{1},x_{2},y_{2}}= \begin{cases} f_{x_{1}-1,y_{1},x_{2},y_{2}+1}+f_{x_{1}-1,y_{1},x_{2}+1,y_{2}}+f_{x_{1},y_{1}-1,x_{2},y_{2}+1}+f_{x_{1},y_{1}-1,x_{2}+1,y_{2}} & A_{x_{1},y_{1}}=A_{x_{2},y_{2}} \\ 0 & A_{x_{1},y_{1}} \ne A_{x_{2},y_{2}} \end{cases}\)
      • 因为合法的路径一定满足 \(x_{1}+y_{1}+x_{2}+y_{2}=n+m+2\) ,故可以省去 \(y_{2}\) 这一维。
    • 在对角线(非严格意义)统计答案即可。
    点击查看代码
    const ll p=993244853;//注意模数不是998244353
    int f[510][510][510];
    char c[510][510];
    int main()
    {
        int n,m,i,j,x1,x2,y1,y2,ans=0;
        cin>>n>>m;
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=m;j++)
            {
                cin>>c[i][j];
            }
        }
        f[1][1][n]=(c[1][1]==c[n][m]);
        for(x1=1;x1<=n;x1++)
        {
            for(y1=1;y1<=m;y1++)
            {
                for(x2=min(n,n+m+2-x1-y1),y2=n+m+2-x1-y1-x2;x2>=x1&&y2<=m;x2--,y2++)
                {
                    if(y2>=1&&c[x1][y1]==c[x2][y2])
                    {
                        f[x1][y1][x2]=(f[x1][y1][x2]+f[x1-1][y1][x2])%p;
                        f[x1][y1][x2]=(f[x1][y1][x2]+f[x1-1][y1][x2+1])%p;
                        f[x1][y1][x2]=(f[x1][y1][x2]+f[x1][y1-1][x2])%p;
                        f[x1][y1][x2]=(f[x1][y1][x2]+f[x1][y1-1][x2+1])%p;
                    }
                }
            }
        }
        for(x1=1;x1<=n;x1++)
        {
            for(y1=1;y1<=m;y1++)
            {
                x2=x1;
                y2=y1;
                if(x1+y1+x2+y2==n+m+2)
                {
                    ans=(ans+f[x1][y1][x2])%p;
                }
                x2=x1+1;
                y2=y1;
                if(x1+y1+x2+y2==n+m+2)
                {
                    ans=(ans+f[x1][y1][x2])%p;
                }
                x2=x1;
                y2=y1+1;
                if(x1+y1+x2+y2==n+m+2)
                {
                    ans=(ans+f[x1][y1][x2])%p;
                }
            }
        }
        cout<<ans<<endl;
        return 0;
    }
    

\(T2\) 快速排序 \(0pts\)

点击查看 qsort/qsort_example.cpp
struct number
{
	bool isnan;
	int value;
};
bool operator < (const number& x, const number& y)
{
	if(x.isnan || y.isnan)
		return false;
	return x.value < y.value;
}
number tmp[1 << 20];
void qsort(number* _begin, number* _end)
{
	if(_begin + 1 >= _end)
		return;
	number a = *_begin, *s = _begin, *t = tmp;
	for(number* p = _begin + 1; p < _end; p++)
	{
		if(*p < a)*s = *p, s++;
		else *t = *p, t++;
	}
	*s = a, s++;
	for(t--; t >= tmp; t--) *(s + (t - tmp)) = *t;
	qsort(_begin, s - 1);
	qsort(s, _end);
}
  • 部分分

    • \(12pts\) :因输入中不包含 nan ,故直接排序即可。
  • 正解

    • 因当 left.isnan=1 时,有 (A[i]<left)=0,故 L+1R 的数都不会被放到 left 前;否则将 L+1R 中小于 left.value 的数从小到大放到 left 前面。
    • multiset 大法好,注意迭代器失效问题。
    点击查看代码
    int b[600000];
    string a[600000];
    multiset<int>vis;
    int main()
    {
        int t,n,i,j,k;
        cin>>t;
        for(i=1;i<=t;i++)
        {
            cin>>n;
            for(j=1;j<=n;j++)
            {
                cin>>a[j];
                if(a[j]!="nan")
                {
                    b[j]=0;
                    for(k=0;k<a[j].size();k++)
                    {
                        b[j]=b[j]*10+a[j][k]-'0';
                    }
                    vis.insert(b[j]);
                }
            }
            for(j=1;j<=n;j++)
            {
                if(a[j]=="nan")
                {
                    cout<<"nan"<<" ";
                }
                else
                {
                    if(vis.find(b[j])!=vis.end())				
                    {
                        while(*vis.begin()<b[j])
                        {
                            cout<<*vis.begin()<<" ";
                            vis.erase(vis.begin());
                        }
                        cout<<b[j]<<" ";
                        vis.erase(vis.find(b[j]));
                    }
                }
            }
            cout<<endl;
        }
        return 0;
    }
    

\(T3\) 混乱邪恶 \(0pts\)

  • 部分分

    • \(0pts\) :输出 Chaotic evil

    • \(97pts\)\(O(2^{n})\) 爆搜。

      点击查看代码
      struct node
      {
          ll x,id;
      }a[2000000];
      ll vis[2000000];
      bool cmp(node a,node b)
      {
          return a.x>b.x;
      }
      bool dfs(ll x,ll n,ll num,ll sum)
      {
          if(num==sum)
          {
              return true;
          }
          else
          {
              if(x==n+1||num>sum)
              {
                  return false;
              }
              else
              {
                  if(dfs(x+1,n,num+a[x].x,sum)==true)
                  {
                      vis[a[x].id]=1;
                      return true;
                  }
                  else
                  {
                      return dfs(x+1,n,num,sum);
                  }
              }
          }
      }
      int main()
      {
          ll n,m,sum=0,i;
          cin>>n>>m;
          for(i=1;i<=n;i++)
          {
              cin>>a[i].x;
              a[i].id=i;
              sum+=a[i].x;
              vis[i]=-1;
          }
          sort(a+1,a+1+n,cmp);
          if(dfs(1,n,0,sum/2)==true)
          {
              cout<<"NP-Hard solved"<<endl;
              for(i=1;i<=n;i++)
              {
                  cout<<vis[i]<<" ";
              }
          }
          else
          {
              cout<<"Chaotic evil"<<endl;
          }
          return 0;
      }
      
  • 正解

    • 2022年普及组1 T2 攻擂?躺平\(01\) 背包做法时间复杂度为 \(O(n^{2}m)\) ,空间复杂度为 \(O(nm)\) ,且难以记录路径,应用至本题会爆炸。
    点击查看官方题解

    点击查看代码
    struct node
    {
        ll x,id;
    }a[2000000],d[2000000];
    ll vis[2000000];
    bool cmp1(node a,node b)
    {
        return a.x<b.x;
    }
    bool cmp2(node a,node b)
    {
        return (a.x==b.x)?(a.id>b.id):(a.x>b.x);
    }
    int main()
    {
        ll n,m,sum=0,i;
        cin>>n>>m;
        for(i=1;i<=n;i++)
        {
            cin>>a[i].x;
            a[i].id=i;
        }
        if(n%2==1)
        {
            n++;
            a[n].x=0;
            a[n].id=n;
        }
        sort(a+1,a+1+n,cmp1);
        for(i=1;i<=n;i++)
        {
            sum+=((i%2==1)?a[i+1].x-a[i].x:0);
            d[i].x=((i%2==1)?a[i+1].x-a[i].x:0x7f7f7f7f);
            d[i].id=i;
            vis[a[i].id]=((i%2==1)?-1:1);
        }
        sort(d+1,d+1+n,cmp2);
        for(i=n/2+1;i<=n&&sum>=1;i++)
        {
            if(sum>=2*d[i].x)
            {
                sum-=2*d[i].x;
                swap(vis[a[d[i].id].id],vis[a[d[i].id+1].id]);
            }
        }
        cout<<"NP-Hard solved"<<endl;
        n-=(a[1].x==0);
        for(i=1;i<=n;i++)
        {
            cout<<vis[i]<<" ";
        }
        return 0;
    }
    

\(T4\) 校门外歪脖树上的鸽子 \(0pts\)

  • 正解

    点击查看官方题解

总结

  • \(T1\)
    • 模数建议复制题面,注意不要打错。
  • \(T2\)
    • 要搞清算法的本质。
    • 要提高读伪代码能力。
posted @ 2024-03-10 18:01  hzoi_Shadow  阅读(31)  评论(0编辑  收藏  举报
扩大
缩小