信友队2024CSP-S第二轮(复赛)模拟赛

2024CSP-S第二轮(复赛)模拟赛

\(T1\) A. 坦白 \(30pts\)

  • 部分分

    • \(30pts\) :爆搜。

      点击查看代码
      ll ans[300010];
      char s[300010];
      int main()
      {
          freopen("confess.in","r",stdin);
          freopen("confess.out","w",stdout);
          ll t,n,cnt,i,j,k;
          __int128_t I=1ull<<63,tmp;
          I*=2;
          scanf("%lld",&t);
          for(k=1;k<=t;k++)
          {
              scanf("%s",s);
              n=strlen(s);
              memset(ans,-0x3f,sizeof(ans));
              for(i=0;i<=(1<<n)-1;i++)
              {
                  tmp=I;
                  cnt=0;
                  for(j=0;j<=n-1;j++)
                  {
                      if((i>>j)&1)
                      {
                          cnt++;
                          tmp^=1;
                      }
                      else
                      {
                          if(s[j]=='+')
                          {
                              tmp++;
                          }
                          else
                          {
                              tmp--;
                          }
                      }
                  }
                  ans[cnt]=max(ans[cnt],(ll)(tmp-I));
              }
              for(i=0;i<=n;i++)
              {
                  printf("%lld ",ans[i]);
              }
              printf("\n");
          }
          fclose(stdin);
          fclose(stdout);
          return 0;
      }
      
    • \(70pts\) :设 \(f_{i,j,0/1}\) 表示前 \(i\) 个数选择了 \(j\) 个数进行异或且是偶数/奇数的最大收益,直接转移即可。

      点击查看代码
      __int128_t f[2][300010][2];
      char s[300010];
      int main()
      {
          freopen("confess.in","r",stdin);
          freopen("confess.out","w",stdout);
          ll t,n,cnt,i,j,k;
          __int128_t I=1ull<<63;
          I*=2;
          scanf("%lld",&t);
          for(k=1;k<=t;k++)
          {
              scanf("%s",s+1);
              n=strlen(s+1);
              memset(f,-0x3f,sizeof(f));
              f[0][0][0]=I;
              for(i=1;i<=n;i++)
              {
                  for(j=0;j<=i;j++)
                  {
                      f[i&1][j][0]=f[(i-1)&1][j][1]+((s[i]=='+')?1:-1);
                      f[i&1][j][1]=f[(i-1)&1][j][0]+((s[i]=='+')?1:-1);
                      if(j-1>=0)
                      {
                          f[i&1][j][0]=max(f[i&1][j][0],f[(i-1)&1][j-1][1]-1);
                          f[i&1][j][1]=max(f[i&1][j][1],f[(i-1)&1][j-1][0]+1);
                      }
                  }
              }
              for(i=0;i<=n;i++)
              {
                  printf("%lld ",(ll)(max(f[n&1][i][0],f[n&1][i][1])-I));
              }
              printf("\n");
          }
          fclose(stdin);
          fclose(stdout);
          return 0;
      }
      
    • \(90pts\) :考虑 Slope Trick 优化上述过程。

  • 正解

    • 因为有 \(2^{64}\) 的进、退位存在,故每次操作都会使数的奇偶性发生变化。
    • 那么 \(\bigoplus\) 放在奇数个事件等价于 \(+1\) ,放在偶数个事件等价于 \(-1\)
    • 统计 \(\bigoplus\) 用来可能和必须更改贡献的次数即可。
    点击查看代码
    char s[300010];
    int main()
    {
        freopen("confess.in","r",stdin);
        freopen("confess.out","w",stdout);
        int t,n,sum,maybe,must,i,j,k;
        cin>>t;
        for(j=1;j<=t;j++)
        {
            cin>>(s+1);
            n=strlen(s+1);
            sum=maybe=must=0;
            for(i=1;i<=n;i++)
            {
                sum+=(s[i]=='+'?1:-1);
                maybe+=((i%2==0&&s[i]=='-')||(i%2==1&&s[i]=='+'));
                must+=(i%2==1&&s[i]=='-');
            }
            for(i=0;i<=must;i++)
            {
                cout<<sum+i*2<<" ";
            }
            for(i=must+1;i<=must+maybe;i++)
            {
                cout<<sum+must*2<<" ";
            }
            for(i=must+maybe;i<=n;i++)
            {
                cout<<sum+must*2-(i-must-maybe)*2<<" ";
            }
            cout<<endl;
        }
        fclose(stdin);
        fclose(stdout);	
        return 0;
    }
    

\(T2\) B. 秘密 \(0pts\)

  • 最左/右边的人一定会往右/左走。

  • \(x\) 向右走为例,设 \(x\) 遇到的第一个人是 \(y\) ,在他们相遇后,让 \(y\) 接着往左走, \(x\) 接着往右走更新其他人。而更新的其他人往哪个方向走已经不重要了,因为完全可以被 \(x,y\) 所替代。

  • 左右两种情况取 \(\min\) 即可。

    点击查看代码
    set<ll>s;
    set<ll>::iterator it;
    int main()
    {
        freopen("secret.in","r",stdin);
        freopen("secret.out","w",stdout);
        ll n,q,x,i;
        double ans;
        char pd;
        cin>>n>>q;
        for(i=1;i<=n;i++)
        {
            cin>>x;
            s.insert(x);
        }
        for(i=1;i<=q;i++)
        {
            cin>>pd>>x;
            if(pd=='+')
            {
                s.insert(x);
            }
            if(pd=='-')
            {
                s.erase(x);
            }
            if(pd=='?')
            {
                ans=0x7f7f7f7f;
                it=s.upper_bound(x);
                if(it!=s.end())
                {
                    ans=min(ans,max(*it-*s.begin(),*(--s.end())-x)/2.0);
                }
                it=s.find(x);
                if(it!=s.begin())
                {
                    it=prev(it);
                    ans=min(ans,max(x-*s.begin(),*(--s.end())-*it)/2.0);
                }
                printf("%.2lf\n",ans);
            }	
        }
        fclose(stdin);
        fclose(stdout);	
        return 0;
    }
    

\(T3\) C. 潜力值 \(0pts\)

  • 部分分

    • 测试点 \(1,2\) :模拟。

      点击查看代码
      const ll p=1000000007;
      ll b[510],id[510];
      deque<ll>q;
      int main()
      {
          freopen("potential.in","r",stdin);
          freopen("potential.out","w",stdout);
          ll n,m,ans=0,i;
          cin>>n>>m;
          for(i=1;i<=n;i++)
          {
              cin>>b[i];
              id[i]=i;
          }
          do
          {
              q.clear();
              for(i=1;i<=m;i++)
              {
                  q.push_back(0);
              }
              for(i=1;i<=n;i++)
              {
                  if(q.front()<b[id[i]])
                  {
                      q.pop_front();
                      q.push_back(b[id[i]]);
                  }
              }
              for(i=0;i<q.size();i++)
              {
                  ans=(ans+q[i])%p;
              }
          }while(next_permutation(id+1,id+1+n));
          cout<<ans<<endl;
          fclose(stdin);
          fclose(stdout);
          return 0;
      }
      
  • 正解

    • 等有时间再来补,先咕了。
    • 挂下 官方题解

\(T4\) D. 括号 \(5pts\)

  • 部分分

    • 测试点 \(6\) :不存在子序列 () ,故输出 \(0\) 即可。
  • 正解

    • 等有时间再来补,先咕了。
    • 挂下 官方题解

总结

  • \(T1\)
    • 因为不想处理负数的异或,所以直接手动判断 \(+/-1\) ,然后就把符号写反了,导致 \(DP\) 没调出来。
    • 观察样例和手摸后发现有一堆连续段,然后就不会做了。
  • \(T2\) 处理传递完消息后的行动方向赛时因为基本没看题所以没去想,要是正儿八经地想或许能想出来。
  • \(T3\) 文件粘成 \(T1\) 文件了,挂了 \(10pts\)
  • \(T4\) 输出文件后缀名写的是输入文件后缀名了,挂了 \(5pts\)
posted @ 2024-10-20 11:15  hzoi_Shadow  阅读(230)  评论(0编辑  收藏  举报
扩大
缩小