HDU 5845 Best Division

$dp$,字典树。

$dp$递推式很容易知道。dp[i]=max{dp[j]+1} a[j]^..^a[i]<=X,并且$[j,i]$长度不能超过$L$。

但是暴力来复杂度极高,所以需要用字典树维护这个东西。将前缀异或和插入到字典树中,然后不断维护$a[i]$位置之前$L$个前缀异或和就好了。

跑了$405ms$,第一次排到第一,有点激动~~~

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
typedef long long LL;
const double pi=acos(-1.0),eps=1e-8;
void File()
{
    freopen("D:\in.txt","r",stdin);
    freopen("D:\out.txt","w",stdout);
}
template <class T>
inline void read(T &x)
{
    char c = getchar(); x = 0;while(!isdigit(c)) c = getchar();
    while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar();  }
}

const LL mod=(LL)268435456;
const int maxn=100010;
LL a[maxn],X,P,Q;
int T,n,L,dp[maxn],h;
struct Node { int cnt,mx,nx[2]; }s[33*maxn];
int sz; bool fail,f[maxn];

int add()
{
    s[sz].mx=0; s[sz].cnt=0;
    s[sz].nx[0]=s[sz].nx[1]=-1; sz++;
    return sz-1;
}

void Delete(LL num)
{
    int p=0;
    for(int i=31;i>=0;i--)
    {
        int x; LL g=(LL)(1<<i); if(num&g) x=1; else x=0;
        int t=p; p=s[p].nx[x]; s[p].cnt--;
        if(s[p].cnt==0) { s[t].nx[x]=-1; return; }
    }
}

void Insert(LL num,int val)
{
    int p=0;
    for(int i=31;i>=0;i--)
    {
        int x; LL g=(LL)(1<<i); if(num&g) x=1; else x=0;
        if(s[p].nx[x]==-1) s[p].nx[x]=add();
        p=s[p].nx[x]; s[p].cnt++; s[p].mx=max(s[p].mx,val);
    }
}

void Find(LL num)
{
    int p=0;
    for(int i=31;i>=0;i--)
    {
        int x; LL g=(LL)(1<<i); if(num&g) x=1; else x=0;
        int y; if(X&g) y=1; else y=0;

        if(y==0)
        {
            p=s[p].nx[x]; if(p==-1) return;
            if(i==0) h=max(h,s[p].mx),fail=0;
        }
        else
        {
            if(s[p].nx[x]!=-1) h=max(h,s[s[p].nx[x]].mx),fail=0;
            p=s[p].nx[x^1]; if(p==-1) return;
            if(i==0) h=max(h,s[p].mx),fail=0;
        }
    }
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%lld%d",&n,&X,&L);
        scanf("%lld%lld%lld",&a[1],&P,&Q);
        for(int i=2;i<=n;i++) a[i]=(a[i-1]*P%mod+Q)%mod;

        sz=0; s[sz].cnt=0; s[sz].nx[0]=s[sz].nx[1]=-1; sz++;

        for(int i=1;i<=n;i++) f[i]=0;
        for(int i=1;i<=n;i++)
        {
            if(i-L-1>=1&&f[i-L-1] ) Delete(a[i-L-1]);
            dp[i]=0; a[i]=a[i]^a[i-1]; if(a[i]<=X) dp[i]=1;
            h=0; fail=1; Find(a[i]); if(fail==0) dp[i]=h+1;
            if(dp[i]!=0) { Insert(a[i],dp[i]); f[i]=1; }
        }

        printf("%d
",dp[n]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zufezzt/p/5789757.html