您的位置:首页 > 移动开发

hdoj Happy Matt Friends 5119 (DP) 好题

2015-10-23 20:47 399 查看

Happy Matt Friends

Time Limit: 6000/6000 MS (Java/Others)    Memory Limit: 510000/510000 K (Java/Others)

Total Submission(s): 1828    Accepted Submission(s): 725


[align=left]Problem Description[/align]
Matt has N friends. They are playing a game together.

Each of Matt’s friends has a magic number. In the game, Matt selects some (could be zero) of his friends. If the xor (exclusive-or) sum of the selected friends’magic numbers is no less than M , Matt wins.

Matt wants to know the number of ways to win.

[align=left]Input[/align]
The first line contains only one integer T , which indicates the number of test cases.

For each test case, the first line contains two integers N, M (1 ≤ N ≤ 40, 0 ≤ M ≤ 106).

In the second line, there are N integers ki (0 ≤ ki ≤ 106), indicating the i-th friend’s magic number.

[align=left]Output[/align]
For each test case, output a single line “Case #x: y”, where x is the case number (starting from 1) and y indicates the number of ways where Matt can win.

[align=left]Sample Input[/align]

2
3 2
1 2 3
3 3
1 2 3

[align=left]Sample Output[/align]

Case #1: 4
Case #2: 2

HintIn the first sample, Matt can win by selecting:
friend with number 1 and friend with number 2. The xor sum is 3.
friend with number 1 and friend with number 3. The xor sum is 2.
friend with number 2. The xor sum is 2.
friend with number 3. The xor sum is 3. Hence, the answer is 4.
题意:给n个数,再给一个m,问有多少种方案,从这n个数中选出若干个(可以是0个),他们的异或值大于等于m。
d[i][j]表示前i个人异或状态为j的方案数。
则 d[i][j] = d[i-1][j] + d[i-1][j^a[i]] 分别表示第i个数不取和第i个数取情况下状态。
//一开始这样写1608Ms
#include<stdio.h>
#include<string.h>
#include<math.h>
#define N 1<<20+1
int dp[41]
;
int a[50];
int main()
{
int t;
int T=1;
int n,m;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
dp[0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=N;j++)
{
dp[i][j]=dp[i-1][j]+dp[i-1][j^a[i]];
}
}
long long cnt=0;
for(int j=m;j<N;j++)
cnt+=dp
[j];
printf("Case #%d: %lld\n",T++,cnt);
}
return 0;
}

//队友用滚动数组写785Ms,我也试了下但还是1700Ms。。。。。(代码基本一样)
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 1<<20+1
using namespace std;
int a[50];
int dp[2]
;
int main()
{
int t;
int T=1;
int n,m,i,j;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
int x=0;
for(i=1;i<=n;i++)
{
x^=1;
for(j=0;j<N;j++)
{
dp[x][j]=dp[x^1][j]+dp[x^1][j^a[i]];
}
}
long long cnt=0;
for(i=m;i<N;i++)
cnt+=dp[x][i];
printf("Case #%d: %lld\n",T++,cnt);
}
return 0;

}

下面的是队友的785Ms。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int INF=0x3f3f3f3f;
const int MAXN=1<<20;
int dp[2][MAXN<<1];//刚开始开到MAXN+10 RE,改成这才对;
int main(){
int T,N,M,flot=0;
int m[41];
scanf("%d",&T);
while(T--){
scanf("%d%d",&N,&M);
memset(dp,0,sizeof(dp));
dp[0][0]=1;
int x=0;
for(int i=0;i<N;i++){
x^=1;
scanf("%d",m+i);
for(int j=0;j<=MAXN;j++){
dp[x][j]=dp[x^1][j]+dp[x^1][j^m[i]];
//代表上一次值为j^m[i]现在再^m[i]等于j了再加上上次j的个数;
}
}
long long ans=0;
for(int i=M;i<=MAXN;i++)ans+=dp[x][i];
printf("Case #%d: %lld\n",++flot,ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: