插头dp入门 hdu 4804 + 5286

论文:http://wenku.baidu.com/view/4fe4ac659b6648d7c1c74633.html


hdu 4804

/*************************************************************************
 > File Name: hdu4804.cpp
 > Author: TechMonster
 > Mail: 928221136@qq.com
 > Created Time: 五  7/ 8 11:43:36 2016
 ************************************************************************/

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<string>
#include<math.h>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
#define ls (o<<1)
#define rs (o<<1|1)
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x, y) memcpy(x, y, sizeof(x))
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int N = 50010;
const int M = 1e9+7;

int n,m,c,d,dp[2][1100][21];
char mp[110][12];
int now,nxt;
void update(int ns,int s,int nk,int k)
{
    if(ns & 1<<m)
    {
        ns ^= 1<<m;
        dp[nxt][ns][nk] += dp[now][s][k];
        if(dp[nxt][ns][nk] > M)    dp[nxt][ns][nk] %= M;
    }
}
void solve()
{
    for(int i = 0; i < n; ++i)
        scanf("%s",mp[i]);
    now = 0,nxt = 1;
    int top = 1<<m;
    MS(dp[nxt],0);
    dp[nxt][top-1][0] = 1;
    for(int i = 0; i < n; ++i)
        for(int j = 0; j < m; ++j)
        {
            nxt ^= 1; now ^= 1;
            MS(dp[nxt],0);
            if(mp[i][j] == '0')
            {
                for(int s = 0; s < top; ++s)
                    for(int k = 0; k <= d; ++k)
                        if(dp[now][s][k]) update(s<<1 | 1,s,k,k);
            }
            else
            {
                for(int s = 0; s < top; ++s)
                    for(int k = 0; k <= d; ++k)
                    {
                        if(!dp[now][s][k]) continue;
                        update(s<<1,s,k,k);
                        if(k < d) update(s<<1 | 1,s,k+1,k);
                        if(j && !(s&1)) update(s<<1 | 3, s, k,k);
                        if(i && !(s & 1<<m-1)) update(s<<1 ^ 1<<m ^ 1, s, k, k);
                    }
            }
        }
    int ans = 0;
    for(int i = c; i <= d; ++i) {
        ans += dp[nxt][top-1][i];
        ans %= M;
    }
    printf("%d\n",ans);
}
int main()
{
    while(~scanf("%d%d%d%d",&n,&m,&c,&d))
        solve();
    return 0;
}



hdu 5286

这题其实没用插头,只用了轮廓线。

状态表示的是,该格子的前m个格子是否被覆盖,0表示没有,1表示有。

前m个是指,先往左,没格子了就从上一层的右边开始接着数

/*************************************************************************
 > File Name: hdu5286.cpp
 > Author: TechMonster
 > Mail: 928221136@qq.com
 > Created Time: 二  7/ 5 20:51:25 2016
 ************************************************************************/

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<string>
#include<math.h>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
#define ls (o<<1)
#define rs (o<<1|1)
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x, y) memcpy(x, y, sizeof(x))
#define PB(x) push_back(x);
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int N = 50010;
const LL M = 1000000007;

int n,m,a[N],b[N],color,vis[N],lim;
vector<LL>Pow[N];
int prefix[250][50010],belong[N];
LL sum[250][250];
void solve()
{
    scanf("%d%d",&n,&m);
    lim = sqrt(n);
    for(int i = 1; i <= n; ++i)
    {
        scanf("%d",&a[i]);
        b[i] = a[i];
        belong[i] = i/lim + 1;
    }
    sort(b+1,b+1+n);
    color = unique(b+1,b+1+n) - b - 1;
    MS(vis,0);
    for(int i = 1; i <= n; ++i)
        a[i] = lower_bound(b+1,b+1+color,a[i]) - b,vis[a[i]]++;
    
    for(int i = 1; i <= color; ++i)
    {
        Pow[i].clear();
        Pow[i].PB(0);
        LL ret = 1,p = b[i];
        for(int j = 1; j <= vis[i]; ++j) ret = (ret*p)%M,Pow[i].PB(ret);
    }
    
    int top = n/lim+1,L,R;
    for(int i = 1; i <= top; ++i)
    {
        memset(vis,0,sizeof(int)*(color+3));
        L = max(1,(i-1)*lim);
        R = min(n,i*lim-1);
        for(int j = 1; j <= color; ++j)
            prefix[i][j] = prefix[i-1][j];
        for(int j = L; j <= R; ++j)
            prefix[i][a[j]]++;
        
        sum[i][belong[L]] = Pow[a[L]][1]; vis[a[L]]++;
        for(int j = L+1; j <= n; ++j)
        {
            sum[i][belong[j]] = (sum[i][belong[j-1]] - Pow[a[j]][vis[a[j]]] + Pow[a[j]][vis[a[j]]+1])%M;
            vis[a[j]]++;
        }
    }
    int la = 0,A,B,c;
    LL ret;
    for(int i = 1; i <= m; ++i)
    {
        scanf("%d%d",&A,&B);
        L = min((A^la)%n,(B^la)%n)+1;
        R = max((A^la)%n,(B^la)%n)+1;
        if(belong[R]-belong[L] <= 1)
        {
            ret = 0;
            memset(vis,0,sizeof(int)*(color+3));
            for(int i = L; i <= R; ++i)
            {
                c = a[i];
                ret = (ret - Pow[c][vis[c]] + Pow[c][vis[c]+1])%M;
                vis[c]++;
            }
        }
        else
        {
            int l = (belong[L])*lim-1, r = belong[R]*lim - lim;
            memset(vis,-1,sizeof(int)*(color+3));
            ret = sum[belong[L]+1][belong[R]-1];
            for(int i = L; i <= l; ++i)
            {
                c = a[i];
                if(vis[c] == -1) vis[c] = prefix[belong[R]-1][c] - prefix[belong[L]][c];
                ret = (ret - Pow[c][vis[c]] + Pow[c][vis[c]+1])%M;
                vis[c]++;
            }
            for(int i = r; i <= R; ++i)
            {
                c = a[i];
                if(vis[c] == -1) vis[c] = prefix[belong[R]-1][c] - prefix[belong[L]][c];
                ret = (ret - Pow[c][vis[c]] + Pow[c][vis[c]+1])%M;
                vis[c]++;
            }
        }
        ret = (ret%M+M)%M;
        la = ret;
        printf("%d\n",la);
    }
    
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
        solve();
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值