hdu 4804 简单插头

本文通过一道南京赛区的算法竞赛题目介绍了插头DP算法的应用。文章详细展示了如何使用该算法解决特定类型的动态规划问题,并提供了完整的代码实现。

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

去年南京赛区的题目,当时还没学过插头dp,虽然白书上有但一下子无法理解其内涵。

学过以后发现这道题就是个裸题。

代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <functional>
#include <sstream>
#include <iomanip>
#include <cmath>
#include <cstdlib>
#include <ctime>
#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
#define INF 1e9
#define MAXN 10000
#define MAXM 100
const int maxn = 1005;
const int mod = 1000000007;
#define eps 1e-6
#define pi 3.1415926535897932384626433
#define rep(i,n) for(int i=0;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define scan(n) scanf("%d",&n)
#define scanll(n) scanf("%I64d",&n)
#define scan2(n,m) scanf("%d%d",&n,&m)
#define scans(s) scanf("%s",s);
#define ini(a) memset(a,0,sizeof(a))
#define out(n) printf("%d\n",n)
//ll gcd(ll a,ll b) { return b==0?a:gcd(b,a%b);}
using namespace std;
ll d[2][25][1<<11];
int n,m,cur,C,D;
void update(int a,int b,int o1,int n1)
{
	if(b & (1<<m)) d[cur][n1][b^(1<<m)] = ( d[cur][n1][b^(1<<m)] + d[1-cur][o1][a]) % mod;
}
char mp[105][15];
int main() {
#ifndef ONLINE_JUDGE  
	freopen("in.txt","r",stdin);  
	//   freopen("out.txt","w",stdout);  
#endif 
	while(~scanf("%d%d%d%d",&n,&m,&C,&D))
	{
	//	if(n < m) swap(n,m);
		rep(i,n) scans(mp[i]);
		ini(d);
		cur = 0;
		d[0][0][(1<<m)-1] = 1;
		rep(i,n) rep(j,m)
		{
			cur ^= 1;
			ini(d[cur]);
			int tp = mp[i][j] - '0';
			if(tp)
			{
				for(int p = 0;p <= D; p++)
				{
					for(int k = 0;k < (1<<m); k++)
					{
						update(k,k<<1,p,p); //bufang
						if(i && !(k&(1<<m-1))) update(k,(k<<1)^(1<<m)^1,p,p);
						if(j && !(k&1)) update(k,(k<<1)^3,p,p);
						if(p && k&(1<<m-1)) update(k,k<<1|1,p-1,p);
					}
				}
			}
			else
			{
				for(int p = 0;p <= D; p++)
				{
					for(int k = 0;k < (1<<m); k++)
					{	
						if(k&(1<<m-1)) update(k,k<<1|1,p,p);
					}
				}
			}
		}
		ll ans = 0;
		for(int i = C;i <= D; i++)
		{
			ans = (ans + d[cur][i][(1<<m)-1]) % mod;
		}
		cout<<ans<<endl;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值