多校联合训练hdu5845---Best Divison

本文探讨了一种结合动态规划(DP)与字典树的数据结构优化方法,通过二分技巧减少状态空间,实现高效的区间划分问题求解。文中详细介绍了如何利用01字典树简化转移操作,并附带了完整的代码示例。

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

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">一个典型的DP</span>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">首先总结一下套路:对于那个所谓的简单问题,必须是2维的,因为需要一维来存取i,另一维来表示当前划分的长度,结果表示花费c。</span>

可以通过二分或者是什么其他的限制答案的方法来消除一维或者是+数据结构简化转移。

然而这个是二分花费导致最后的一维减少。那么就是,i一维,结果保存一维,这样的话就可以简化一维。

。。。。。。其实要划分区间,那么套路就是这样的。那也就是d[i] --- d[j] 和 那个。但是存的是划分的次数。。。。

再加上一个01字典树的应用。。。就可以简化转移。。。为0(32) ;

但是怎么写都错,要加强代码的训练。而且必须是有思想的训练。。。

#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")

using namespace std;
#define   MAX         100005
#define   MAXN        2000005
#define   maxnode     500010
#define   sigma_size  30
#define   lson        l,m,rt<<1
#define   rson        m+1,r,rt<<1|1
#define   lrt         rt<<1
#define   rrt         rt<<1|1
#define   mid         int m=(r+l)>>1
#define   LL          long long
#define   ull         unsigned long long
#define   mem0(x)     memset(x,0,sizeof(x))
#define   mem1(x)     memset(x,-1,sizeof(x))
#define   meminf(x)   memset(x,INF,sizeof(x))
#define   lowbit(x)   (x&-x)
#define   S(n)        scanf("%d",&n)
#define   P(n)        printf("%d ",n)
#define   PN(n)       printf("%d\n",n)
#define   FP(k)       freopen(k , "r" ,stdin)
#define   RPTI(s , n) for(int i=s;i<n;i++)
#define   RPTJ(s , n) for(int j=s;j<n;j++)
#define   RPTK(s , n) for(int k=s;k<n;k++)
#define   RPTL(s , n) for(int l=s;l<n;l++)
const LL     mod   = 1000000;
///const int    prime = 999983;
const int    INF   = 0x3f3f3f3f;
const int    INFF  = 1e9;
const double pi    = 3.141592653589793;
const double inf   = 1e18;
const double eps   = 1e-10;
inline int read_int(){
    int ret=0;
    char tmp;
    while(!isdigit(tmp=getchar()));
    do{
        ret=(ret<<3)+(ret<<1)+tmp-'0';
    }
    while(isdigit(tmp=getchar()));
    return ret;
}
/*******************************************/
typedef long long ll ;
typedef pair <int ,int> pii ;
#define mk make_pair
const ll moddd = 268435456 ;
struct trie
{
    int ch[MAX][2],tot;
    int val[MAX],dp[MAX],fa[MAX];
    void build()
    {
        memset(ch,0,sizeof(ch));
    	memset(val,0,sizeof(val));
    	memset(dp,-1,sizeof(dp));
    	memset(fa,0,sizeof(fa));
        tot = 1;
    }
    void insert(int s,int Val,int dpval)
    {
        int u = 0;
        for(int i = 30;i >= 0;i--)
        {
            int v = ((1<<i) & s) ? 1 : 0;
            if(!ch[u][v])
			{
				fa[tot] = u;
				ch[u][v] = tot++;
			}
            u = ch[u][v];
            val[u] += Val;
            dp[u] = max(dp[u],dpval);
        }
		if(!val[u])
		{
			dp[u] = -1;
			while(u)
			{
				u = fa[u];
				dp[u] = -1;
				if(ch[u][0] && val[ch[u][0]]) dp[u] = dp[ch[u][0]];
				if(ch[u][1] && val[ch[u][1]]) dp[u] = max(dp[u],dp[ch[u][1]]);
			}
		}
    }
    int find(int s , int x)
     {
		int u = 0,ans = -1;
		bool flag = false;
		for(int i = 30;i >= 0;i--)
		{
			int v = ((1<<i) & s) ? 1 : 0;
			int V = ((1<<i) & x) ? 1 : 0;
			if(V && ch[u][v] && val[ch[u][v]]) ans = max(ans,dp[ch[u][v]]);
			u = ch[u][V ^ v];
			if(!u || !val[u]) break;
			if(i == 0) flag = true;
		}
		if(flag) ans = max(ans,dp[u]);
		return ans;
    }
} tree;
ll arry[200000] ;
ll sum[200000] ;
ll dp[200000] ;
int main(){
    int T ; scanf("%d" , &T) ; 
    while(T --){
        int n , x , l ; scanf("%d%d%d" , &n,&x,&l) ;
        int ta ,tb ,tc ; scanf("%d%d%d" , &ta,&tb,&tc) ;
        tree.build() ;
        arry[1] = ta ;
        sum[1] = arry[1] ;
        for(int i=2;i<=n;i++){
            arry[i] = arry[i-1] * tb + tc ; arry[i] %= moddd ;
            sum[i] = sum[i-1] ^ arry[i] ;
        }
        tree.insert(0 , 1 , 0) ;
        dp[0] = 0 ;
        sum[0] = 0 ;
        for(int i=1;i<=n;i++){
            if(i-l-1 >= 0 && dp[i-l-1] >= 0) tree.insert(sum[i-l-1] , -1 , -1) ;
            int tmp = tree.find(sum[i] , x) ;
            dp[i] = tmp + 1 ;
            if(tmp == -1) {
                dp[i] = -1 ;continue ;
            }
            tree.insert(sum[i] , 1 , dp[i]) ;
            //cout << i <<" "<<sum[i]<< " " << dp[i] << endl ;
        }
        if(dp[n] == -1) dp[n] = 0 ;
        cout << dp[n] << endl ;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值