Processing math: 100%

嘘~ 正在从服务器偷取页面 . . .

洛谷_


洛谷P8941 [SSOI 2023 easy Round] D. Goodbye 2022 题解

题目链接:P8941 [SSOI 2023 easy Round] D. Goodbye 2022

题意

给定 n,k,p,求有多少有序 p 元组 (a1,a2,,ap) 满足

  • i[1,p]ai[1,n]

  • i[1,p)popcount(aiai+1)=k

  • i,j[1,p],ijaiaj

答案对 998244353 取模。

  • 其中 popcount(x) 表示 x 在二进制表达下 1 的个数。
  • 表示按位异或操作。
  • 两个有序 p 元组 (a1,a2,,ap)(b1,b2,,bp) 不同当且仅当存在 i[1,p] 使得 aibi

输入格式

一行三个正整数 n,k,p

输出格式

一行一个数,表示答案。

数据范围

对于所有测试数据,保证 1n10001klog2n1p5

注意到 n 很小,所以记一个bitset<N> b[N]bi,j=[popc(ij)=k] ,然后暴力算出来,并记

fi=nj=1[popc(ij)=k]=popc(bi)gi,j=nl=1[popc(il)=kpopc(jl)=k]=popc(bi&bj)

接着分类讨论 p 的情况。

  • p=1 ,答案为 n

  • p=2 ,枚举 a1 ,答案为 ni=1fi

  • p=3 ,枚举 a2 ,则 a1 的方案数为 fa2a3 的方案数为 fa21 ,故答案就是 ni=1fi(fi1)

  • p=4 ,枚举 a2,a3 ,显然 ba2,a3=True ,否则不合法。

    此时 a1 取值有 fa21 个(因为 a1a3),a4 取值有 fa31 个( 因为 a2a4

    统计时再去掉 a1=a4 的情况,答案就是 ni=1nj=1[bi,j=True]×[(fi1)(fj1)gi,j)]

  • p=5 ,枚举 a2,a4 ,进一步分类讨论 ba2,a4

    • ba2,a4=True ,此时 a1 的取值有 fa22 个(除了 a3,a4),a5 同理有 fa42 个。
    • ba2,a4=False ,此时 a1 的取值有 fa21 个(除了 a3),a5 同理有 fa41 个。

    去掉 a1=a5 的情况,由于 a3 已经占用了一个 ga2,a4 的位置,故该情况有 ga2,a41 个,则

    {gi,j×[(fi2)(fj2)(gi,j1)],ba2,a4=Truegi,j×[(fi2)(fj2)(gi,j1)],ba2,a4=False

时间复杂度 O(n3ω)

代码:

cpp
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
const int mod = 998244353;
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
void add(int &x, int y) { (x += y) >= mod ? x -= mod : 0; }
#define popc(x) __builtin_popcountll(x)
#define N ((int)(1e3 + 15))

bitset<N> b[N];
int n,k,p,res,f[N],g[N][N];
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n >> k >> p;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++) b[i][j] = (popc(i ^ j) == k);
    for(int i = 1; i <= n; i++) f[i] = b[i].count();
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++) g[i][j] = (b[i] & b[j]).count();
    if(p == 1) return cout << (res = n) << '\n', 0;
    if(p == 2) { for(int i = 1; i <= n; i++) add(res, f[i]); cout << res << '\n'; }
    else if(p == 3) {
        for(int i = 1; i <= n; i++) add(res, f[i] * (f[i] - 1) % mod);
        cout << res << '\n';
    }else if(p == 4) {
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++) if(b[i][j])
                add(res, (((f[i] - 1) * (f[j] - 1) - g[i][j]) % mod + mod) % mod);
        cout << res << '\n';
    }else if(p == 5) {
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++) if(i != j) {
                int x = (f[i] - (b[i][j] ? 2 : 1)) * (f[j] - (b[i][j] ? 2 : 1)) % mod;
                add(res, (g[i][j] * (x - g[i][j] + 1) % mod + mod) % mod);
            }
        cout << res << '\n';
    }
    return 0;
}

参考文献

[1] P8941 题解 - kbtyyds 的博客 - 洛谷博客


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
你认为这篇文章怎么样?
  • 0
  • 0
  • 0
  • 0
  • 0
  • 0
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v3.1.3
  目录