zoukankan      html  css  js  c++  java
  • hihocoder 1279(状压)

    坑爹的题目。不过不能说不是一道挺好的题目。

    坑主要坑在,妹的我一样的复杂度,写的姿势略差了点然后就一直超时。

    比赛的时候我还直接就看错题目,把AND运算看成了OR。。。还敲完交了一发。

    这题很容易想到:

    因为给出的数字只有13位,所以每位用2位二进制表示。

    如:

    00 1的个数为偶数,最后的结果为0

    01 1的个数为奇数,最后的结果为0

    10 1的个数为偶数,最后的结果为1

    11 1的个数为奇数,最后的结果为1

    这样就可以转移求出最后的结果。然而这样做的复杂度是O(50*2^26)>1e9. 肯定不行。

    仔细想想我们可以发现,当出现了0以后结果一定为0。这样用2位二进制位表示这个信息有些多余了。我们可以用三进制0,1,2和多余附加的一个标志位来表示这种信息。

    如果某一位一直都是1则用0表示,如果出现了0,则用1,2分别代表出现奇数个1和偶数个1。 再配上附加的标志位来记录当前为止已加入数个数的奇偶性。分析下就可以发现,这样是能够把每一种情况表示出来的。

    原先得用2^26=67108864种状态表示,现在只需要2*3^13=3188646. 直接就相差了20倍。wonderful!

    然后剩下来还有一个关键问题,怎样将转移的O(13)->O(1)

    PS:我原先的思想是,预处理,对于2*3^13的每种状态对应2^26某一种。结果一直TLE,这种做法会有比较大的内存消耗,而且预处理时间也较长。

    可以预处理7位的所有情况,也就是把13位分成两半,因为对这两半的操作都是一样的,所以只需要预处理一半就行了,然后空间消耗变得非常小,转移操作变成O(1).

    Rikka with Sequence

    时间限制:20000ms
    单点时限:2000ms
    内存限制:512MB

    描述

    众所周知,萌萌哒六花不擅长数学,所以勇太给了她一些数学问题做练习,其中有一道是这样的:

    勇太有n个[0,8192)中的整数,现在六花可以从中选出若干个数(不可以不取),她的方案需要满足她选出的所有数的异或和恰好等于它们AND(二进制与运算)起来的值,现在勇太想让六花求出满足条件的方案数。

    当然,这个问题对于萌萌哒六花来说实在是太难了,你可以帮帮她吗?

    输入

    第一行一个整数n,接下来一行里n个整数。

    1<=n<=50

    输出

    输出一行表示答案。

    样例输入
    3
    1 1 1
    
    样例输出
    4


    //
    //  main.cpp
    //  hiho19
    //
    //  Created by 陈加寿 on 16/3/20.
    //  Copyright © 2016年 chenhuan001. All rights reserved.
    //
    
    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <vector>
    #include <time.h>
    #include <math.h>
    #include <algorithm>
    using namespace std;
    
    #define K 8200
    
    int g[55];
    long long dp[2][1600000][2];
    int chg[2200][130][2];
    int chg1[2200][130][2];
    
    void init()
    {
        int save[15];
        memset(save,0,sizeof(save));
        for(int i=0;i<2187;i++)
        {
            for(int j=0;j<(1<<7);j++)
            {
                for(int p=0;p<2;p++)
                {
                    //然后你想怎么搞就怎么搞吧。
                    int tmp1=0,tmp2=0;
                    for(int k=0;k<7;k++)
                    {
                        if(save[k] == 0)
                        {
                            tmp1 |= (1<<k);
                        }
                    }
                    for(int k=0;k<7;k++)
                    {
                        if(save[k] == 0)
                        {
                            if(p) tmp2|=(1<<k);
                        }
                        else if(save[k] == 1) tmp2|=(1<<k);
                    }
                    tmp1 &= j;
                    tmp2 ^= j;
                    //然后再转变回去。
                    int tmp=1;
                    int sum=0;
                    for(int k=0;k<7;k++)
                    {
                        if( (tmp1&(1<<k))!= 0)
                        {
                            ;
                        }
                        else if( (tmp2&(1<<k))!= 0 )
                        {
                            sum += tmp;
                        }
                        else if( (tmp2&(1<<k))== 0 )
                        {
                            sum += 2*tmp;
                        }
                        tmp *=3;
                    }
                    chg[i][j][p] = sum;
                    chg1[i][j][p] = (chg[i][j][p]/3)*2187;
                }
            }
            
            int tj=0;
            save[tj]++;
            while(save[tj]>=3)
            {
                save[tj+1]++;
                save[tj]=0;
                tj++;
            }
    
        }
    }
    
    //是与运算
    //clock_t be,ed;
    //void checktime()
    //{
    //    ed=clock();
    //    cout<<(double)(ed-be)/CLOCKS_PER_SEC<<endl;
    //    be=clock();
    //    
    //}
    int main() {
        //看错题目??? 不思考看题解??? 你是SB吗
        int n;
        cin>>n;
        
        // 我真是日了狗了
        for(int i=0;i<n;i++)
        {
            scanf("%d",g+i);
            //13 = 1594323(nn,13);
            //1594323 = 1594323(1594323,tcnt);
        }
        //    if(13 == 0)
        //    {
        //        cout<<((1LL)<<n)-1<<endl;
        //        return 0;
        //    }
        
        //be=clock();
        init();
        //checktime();
        
        int a=0;
        memset(dp,0,sizeof(dp));
        dp[a][0][0] = 1;
        
        for(int i=0;i<n;i++)
        {
            memset(dp[a^1],0,sizeof(dp[a^1]));
            
            int up=g[i]>>6;//这个应该是移6位吧
            int down = g[i]&((1<<7)-1);
            
            int j1=0,j2=0;
            for(int j=0;j<1594323;j++)
            {
                j2= j/729; j1=j%2187;
                for(int p=0;p<2;p++)
                {
                    //dp[a^1][j] += dp[a][j];
                    int sum=0;
                    if(dp[a][j][p] != 0)
                    {
                        dp[a^1][j][p] += dp[a][j][p];
                        sum = chg1[j2][up][p]+chg[j1][down][p];
                        dp[a^1][sum][p^1] += dp[a][j][p];
                    }
                    
                }
    //            j2++;
    //            if(j2>=(2187))
    //            {
    //                j2=0;j1++;
    //            }
            }
            a = a^1;
        }
        //checktime();
        
        long long ans=0;
        int save[15];
        memset(save, 0, sizeof(save));
        for(int j=0;j<1594323;j++)
        {
            for(int p=0;p<2;p++)
            {
                int flag=0;
                for(int k=0;k<13;k++)
                    if(save[k]==1)
                    {
                        flag=1;
                        break;
                    }
                    else if(save[k]==0 && p==0)
                    {
                        flag=1;
                        break;
                    }
                
                if(flag==0) ans += dp[a][j][p];
            }
            int tj=0;
            save[tj]++;
            while(save[tj]>=3)
            {
                save[tj+1]++;
                save[tj]=0;
                tj++;
            }
        }
        //checktime();
        
        cout<<ans<<endl;
        
        return 0;
    }
  • 相关阅读:
    Ubuntu杂记——Ubuntu自带拼音输入发杂乱不堪
    数据库随笔——数据库设计原则(转)
    Java学习笔记——回调函数
    Android随笔之——静默安装、卸载
    Hibernate学习之——搭建log4j日志环境
    Hibernate学习之——Hibernate环境搭建
    Android随笔之——闹钟制作铺垫之AlarmManager详解
    Android随笔之——Android时间、日期相关类和方法
    Nyoj 天下第一(spfa)
    hdu 最大三角形(凸包+旋转卡壳)
  • 原文地址:https://www.cnblogs.com/chenhuan001/p/5305845.html
Copyright © 2011-2022 走看看