hdu 4901 The Romantic Hero 2014 Multi-University Training Contest 4 E

题目链接:2014多校四-1005

        CLJ大大所说的送分题,硬是想了好久好久。。。。。orz

        给定n个数,从中选出S、T两个区间,要求保证S中所有数都在T中所有数的左侧。对S中的所有数做异或操作,对T中的所有数做位与操作,问使得两个结果相同的选法一共有多少种。

解题思路:DP,DP[i][j]表示选到i位置为止,异或值为j有多少种情况。然后依据右端取得j的情况数求最终结果

/*********************************************************************
  FileName: 1005.cpp
  Author: wing
  Created Time: 2014年07月31日 星期四 12时51分14秒
*********************************************************************/

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mod 1000000007
#define FFF 1005
int n;
int a[FFF];
long long dp[FFF][1024];//长度为i,异或值为j的有多少种情况
long long sum[FFF][1024];//选用i位置的数,相与得j的有多少种情况
//直接开long long 不然会炸int
int main()
{
	int keng;
	scanf("%d",&keng);
	while(keng--)
	{
		memset(dp,0,sizeof(dp));
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
		}
		dp[1][a[1]]=1;
		for(int i=2;i<=n;i++)
		{
			dp[i][a[i]]+=1;//之前的数都不选用,只用i位置的数的情况
			for(int j=0;j<1024;j++)
			{
				dp[i][j]+=dp[i-1][j];//i位置的数不选用,得到异或值为j的情况
				dp[i][j]%=mod;
				dp[i][(j^a[i])]+=dp[i-1][j];//选用了i位置,得到异或值为j^a[i]的情况
				dp[i][(j^a[i])]%=mod;
			}
		}
		//debug
	/*	for(int i=1;i<=4;i++)
		{
			for(int j=0;j<4;j++)
				cout<<dp[i][j]<<' ';
			cout<<endl;
		}cout<<endl;
	*/
		memset(sum,0,sizeof(sum));
		sum[n][a[n]]=1;
		long long ans=0;
		ans+=dp[n-1][a[n]];
		for(int i=n-1;i>1;i--)
		{
			sum[i][a[i]]+=1;
			for(int j=0;j<1024;j++)
			{
				sum[i][(j&a[i])]+=sum[i+1][j];//选用了a[i]的情况
				sum[i][(j&a[i])]%=mod;
			}
			for(int j=0;j<1024;j++)
			{
				ans=(ans+sum[i][j]*dp[i-1][j]%mod)%mod;//为保证不重复,计算时只考虑选用了a[i]的情况
				sum[i][j]+=sum[i+1][j];
				sum[i][j]%=mod;
			}
		}
		//debug
	/*	for(int i=1;i<=4;i++)
		{
			for(int j=0;j<10;j++)
				cout<<sum[i][j]<<' ';
			cout<<endl;
		}*/
		cout<<ans<<endl;
	}
	return 0;
}
P.S. 计数数组要开long long,开int的时候炸了一次,第N次在long long上吃亏了

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值