[CTSC2017]吉夫特

本文介绍了一种使用分块DP解决特定类型问题的方法,通过将数字分为前后两段,并利用f[u][v]来记录状态,实现了高效求解。文章详细解释了如何更新状态以及时间复杂度分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一道不难但是拖了很久的题,我这个傻逼活该要退役.

Click here to read the problem.

N=log2(maxai) N = l o g 2 ( m a x a i ) .
网上很多 3N 3 N 的做法,不具体说了,大概就是 dp[x] d p [ x ] 代表以 x x 结尾的方案数.

考虑分块,把数字二进制下分成前一段和后一段.
f[u][v]=vxdp[u2N2+x].即前一半为 u u ,后一半v的超集的方案数之和.(超集就是子集的补集).

每加进一个数字,枚举前一半的超集,计算答案;再枚举后一半的子集,因为这个数字结尾的答案将影响后一半子集的 f f 值.

时间复杂度O(6N2).

#include <bits/stdc++.h>
#define LL long long
using namespace std ;
template <class T> void Read ( T &x, char c = getchar(), bool f = 0 ) {
    for ( x = 0 ; !isdigit(c) ; c = getchar() ) f |= c == '-' ;
    for ( ; isdigit(c) ; c = getchar() ) x = 10*x + c - '0' ;
    if (f) x = -x ;
}
const int maxn = 220000, Mod = 1000000007 ;
int n, m, S, f[520][520] ;
int main() {
    int i, x, u, v, val, ans = 0 ;
    Read(n) ;
    m = 1<<9, S = m-1 ;
    for ( i = 1 ; i <= n ; i ++ ) {
        Read(x) ;
        u = x/m, v = x%m ;
        val = 1 ;
        for ( x = u^S ; x ; x = (x-1)&(u^S) )
            if (f[x|u][v]) (val += f[x|u][v]) %= Mod ;
        (val += f[u][v]) %= Mod ;
        for ( x = v ; x ; x = (x-1)&v ) (f[u][x] += val) %= Mod ;
        (f[u][0] += val) %= Mod ;
    }
    for ( i = 0 ; i <= S ; i ++ )
        (ans += f[i][0]) %= Mod ;
    (ans += Mod-n) %= Mod ;
    cout << ans << endl ;
    return 0 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值