HDU-4901 The Romantic Hero DP

47 篇文章 0 订阅
33 篇文章 2 订阅

首先吐槽一下这个神一样的题目前缀,特么一直在强调萝莉控是闹哪样啊喂(╯‵□′)╯︵┻━┻

题意不难,从一个数列中选出一部分作为S,S的元素进行 ‘异或’ 操作,在选出一部分作为T,T里的元素进行 ’与‘ 操作,要求S的元素必须在T的元素的左边。

最初没有想到用DP写,因为没有想到用下标表示数字,其实用用二维数组DP,横坐标表示操作到第几个数,纵坐标储存该数字得到多少次,最开始把初状态放进去就好,最后对应位置相乘加起来就好了,G++TLE了,换成C++2437ms过了,另外写的时候思路还不是很清晰,代码很乱。

#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iomanip>
using namespace std;
const int mod=1000000000+7;
long long dp1[1111][1111];
long long dp3[1111][1111];
long long dp2[1111][1111];
long long m1[2048];
long long m2[2048];
int a[1111];
int n;
long long sum;
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		memset(dp1,0,sizeof(dp1));
		memset(dp2,0,sizeof(dp2));
		memset(dp3,0,sizeof(dp3));
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
		}
		dp1[1][a[1]]=1;//初状态处理 
		dp3[1][a[1]]=1;
		//dp1[1][0]=1;
		dp2[n][a[n]]=1;
		//dp2[n][0]=1;
		for(int i=2;i<n;i++)
		{
			dp3[i][a[i]]+=1;//用来表示前几个都不取的情况 
			dp1[i][a[i]]+=1;
			memset(m1,0,sizeof(m1));
			for(int j=0;j<=1024;j++)
			{
				if(dp1[i-1][j]!=0)
				{
					
					dp3[i][a[i]^j]+=dp1[i-1][j];//用另一个DP储存,因为最后处理时要求最后一个必须取到 
					dp1[i][a[i]^j]+=dp1[i-1][j];
					dp1[i][a[i]^j]%=mod;
					dp3[i][a[i]^j]%=mod;
					m1[j]=dp1[i-1][j];
					m1[j]%=mod;
				}
			}
			for(int j=0;j<=1024;j++)
			{
				dp1[i][j]+=m1[j];
				dp1[i][j]%=mod;//处理到第i个的总情况 
			}
		}
		for(int i=n-1;i>1;i--)
		{
			dp2[i][a[i]]+=1;//用来表示前几个都不取的情况 
			memset(m2,0,sizeof(m2));
			for(int j=0;j<=1024;j++)
			{
				if(dp2[i+1][j]!=0)
				{
					dp2[i][a[i]&j]+=dp2[i+1][j];//后面的只需要保证不为空就行了,不需要特殊处理 
					dp2[i][a[i]&j]%=mod;
					m2[j]=dp2[i+1][j];
					m2[j]%=mod;
				}
			}
			for(int j=0;j<=1024;j++)
			{
				dp2[i][j]+=m2[j];
				dp2[i][j]%=mod;
			}
		}
		sum=0;
		for(int i=1;i<n;i++)
		{
			for(int j=0;j<=1024;j++)
			{
				if(dp3[i][j]&&dp2[i+1][j])
				{
					sum+=dp3[i][j]*dp2[i+1][j];//对应位置相乘相加,+1刚好是所有的情况 
					sum%=mod;
				}
			}
			//cout<<sum<<endl;
		}
		cout<<sum<<endl;
	}
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值