1 条题解

  • 0
    @ 2026-5-28 17:14:53

    去打 Silver 了。

    凭什么去年我打 Bronze 时是绿黄黄,这次是橙黄黄,第一题不应该最难吗!

    实际上这一题纯诈骗,就是个爆搜,你再有注意力也很难找到多项式时间复杂度的做法。最朴素的做法是 dfs 枚举格子的情况,然后每种情况都要花 O(k)O(k) 的时间计算得分,再更新答案,这样时间复杂度显然是 O(2nk)O(2^n k) 的。注意到 nn 不超过 2020,因此 2n2^n 的部分优化效果不大,而 kk 可以达到 2×1052\times 10^5 级别,优化可以从这里入手。如果注意力惊人可以发现,由于每次移动只会点击三个位置,而每个位置只有 nn 种选择,所以不同的移动次数最多只有 O(n3)O(n^3) 级别,因此我们把每种不同情况的移动次数记录下来,这样就不用花 O(k)O(k) 的时间计算分数了,搜索时可以把是 M/OM/O 的格子的位置记录下来存在 vector 里,然后最后计算分数时枚举 MM 的位置表示移动点击的第一个位置,再枚举 OO 的位置表示移动点击的第三个位置,再枚举另一个 OO 的位置表示移动点击的第三个位置。这样时间复杂度只有 O(2nn3)O(2^n n^3) 了。

    AC Code:(C++11)

    #include<iostream>
    #include<stdlib.h>
    #include<algorithm>
    #include<string.h>
    #include<numeric>
    #include<vector>
    #include<set>
    #include<queue>
    using namespace std;
    int n,k,bestScore,bestCnt;
    int cnt[25][25][25];
    vector<int> mp,op;
    void dfs(int id=1) {
      if(id>n) {
        int score=0;
        for(int i=0;i<mp.size();i++)
          for(int j=0;j<op.size();j++) {
            for(int g=j+1;g<op.size();g++)
              score=score+cnt[mp[i]][op[j]][op[g]];
    	  }
    	if(score>bestScore) {
          bestScore=score;
          bestCnt=1;
    	}
    	else
    	if(score==bestScore)
    	  bestCnt++;
    	return;
      }
      mp.emplace_back(id);
      dfs(id+1);
      mp.pop_back();
      op.emplace_back(id);
      dfs(id+1);
      op.pop_back();
    }
    int main() {
      ios::sync_with_stdio(0);
      cout.tie(0);
      cin>>n>>k;
      for(int i=1,x,y,z;i<=k;i++) {
        cin>>x>>y>>z;
        if(y>z)
          swap(y,z);
        cnt[x][y][z]++;
      }
      dfs();
      cout<<bestScore<<' '<<bestCnt<<'\n';
    }
    
    
    • 1

    信息

    ID
    5546
    时间
    2000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    2
    已通过
    1
    上传者