HDU5119 Happy Matt Friends

题目大意:

      Matt的n个朋友都有数字,Matt可以选其中几个(可以是零)异或起来,若结果不小于数m,Matt就赢,问Matt赢的方法数。(1 ≤ N ≤ 40, 0 ≤ M ≤ 10 6).

思路:

          f[i][j]表示到第i个朋友,异或结果为j的方法数。

          转移方程:f[i][j]=f[i-1][j^a[i]]+f[i-1][j]。

 

我的代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cstdlib>
 5 #include<iostream>
 6 
 7 using namespace std;
 8 
 9 const int maxn=(1<<20);
10 
11 long long f[41][maxn+1];
12 int T,n,m,a[41];
13 
14 int main()
15 {
16     scanf("%d",&T);
17     for(int  I=1;I<=T;I++)
18     {
19         scanf("%d%d",&n,&m);
20         for(int i=1;i<=n;i++)
21         {
22             scanf("%d",&a[i]);
23         }
24         memset(f,0,sizeof(f));
25         f[0][0]=1;
26     //    cout<<f[n][maxn];
27         for(int i=1;i<=n;i++)
28         {
29              for(int j=0;j<maxn;j++)
30              {
31                  f[i][j]=f[i-1][j^a[i]]+f[i-1][j];
32              }
33         }
34         //cout<<f[n][maxn];
35         long long ans=0;
36         for(int i=m;i<maxn;i++)
37         {
38             ans=f[n][i]+ans;
39           //  printf("::%I64d\n");
40         }
41         printf("Case #%d: %I64d\n",I,ans);
42     }
43     return 0;
44     
45 }
View Code

如果有不幸的同学一直TLE,就试试滚动数组吧(或者用下述方法)。

//队友最初的代码(没改滚动数组版)(加了读入优化,只循环1000000,竟然还TLE):

 1 #include<iostream>
 2 #include<cstdio> 
 3 #include<cstdlib>
 4 #include<cstring>
 5 using namespace std;
 6 const int maxm=1<<(20);
 7 long long f[maxm][41]; 
 8 int n,m,t;
 9 int num[41];
10 
11 int getint()
12 {
13     char ch=getchar();
14     while(ch<'0'||ch>'9')ch=getchar();
15     int ret=0;
16     while(ch>='0'&&ch<='9')
17     {
18         ret=ret*10+ch-'0';
19         ch=getchar();
20     }
21     return ret;
22 }
23 
24 int main()
25 {
26     t=getint();
27     for(int i=1;i<=t;i++)
28         {    
29             memset(f,0,sizeof(f));
30             long long ans=0; 
31             f[0][0]=1; 
32             n=getint();
33             m=getint();
34             for(int j=1;j<=n;j++)
35                 {
36                     num[j]=getint();
37                 }
38             for(int j=1;j<=n;j++)
39                 {    
40                     for(int cl=0;cl<=1000000;cl++)
41                     {
42                             f[cl][j]=f[cl][j-1]+f[cl^num[j]][j-1];                    
43                     }
44                     
45                 }
46             for(int k=m;k<=1000000;k++)
47             ans+=f[k][n];
48             printf("Case #%d: %I64d\n",i,ans);
49         }
50     return 0;
51 }
View Code

 队友代码主要的问题就是f[i][j]中用j表示朋友,用i表示异或和,要是换过来就a了。

专门测了一下,将数组中小的开在前面比大的开在前面快得多,先循环数组前面得一维要比先循环后面一维快得多。

posted @ 2018-10-06 22:33  liqgnonqfu  阅读(109)  评论(0编辑  收藏  举报