1. 程式人生 > >多校聯合訓練2016---hdu5798Stabliztion

多校聯合訓練2016---hdu5798Stabliztion

一個壓縮狀態 + 記憶搜尋/DFS非順序列舉 的題目。。

TLE的同學記得一定要用G++提交。否者如果是C ++ ,標程都TLE。表示時間限制很緊,標程都是1800ms,我的是2800ms......

首先很容易想到的思路是,,X的每一位如果是1.都會對10^5個數產生影響。。記錄變化下來,然後列舉X,再迴圈x的每一位,如果是1,就加上這個變化。。

但是也就自然的把10^5-1個差壓縮成了d[20],也就是i位變化,所有的數的變化和。。。

但是考慮到,如果兩個相鄰的數。他們的最高的不同位發生了變化,那麼兩個的相對大小會發生變化。。那麼之前求的j位(j < i)變化,要取反。。。

這樣就加加入了一維。。d[i][j]表示最高不同位是i的所有數。。j位發生變化產生的總的影響是多少。。其實也就相當於是求貢獻。。每一個數的貢獻和就是結果,但是每一個數都有些許不同(最高不同位)這樣就要分開來。所以引入了那個陣列。這個思想是很重要的,也是找出狀態的關鍵。。

有了d陣列,這樣的話。樸素列舉每一個x,每一個x中在對d的兩維列舉,滿足條件就+d[i][j],但是注意取反的情況,這樣也就很簡單了。

可是20*20*2^20會超時。。。

考慮優化:找出不同的x中,有沒有共同點。。因為

0000100010101

1010100010101

對於上面兩個資料,考慮第一個數第一個1時,如果算出來了,那麼對於下面的第3個1,因為後面完全相同,雖然前面不同,但是因為最高位是在後面。,這些不同的位不產生影響。所以,還是相等的。。。

這樣考慮記錄陣列t[20][2^20]。。。記錄資料。,。

然後發現會超空間。。。

但是用貢獻的思路考慮。先列舉x,在列舉i,和先列舉i然後在列舉x,對於每一個x貢獻是一樣的。。

所以可以改變列舉順序。。。。(很重要的思路) ; 

就可以把t陣列變為t[2^20] ; 很叼的題目。。很好。。。

#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")

using namespace std;
#define   MAX         1000005
#define   MAXN        2000005
#define   maxnode     500010
#define   sigma_size  30
#define   lson        l,m,rt<<1
#define   rson        m+1,r,rt<<1|1
#define   lrt         rt<<1
#define   rrt         rt<<1|1
#define   mid         int m=(r+l)>>1
#define   LL          long long
#define   ull         unsigned long long
#define   mem0(x)     memset(x,0,sizeof(x))
#define   mem1(x)     memset(x,-1,sizeof(x))
#define   meminf(x)   memset(x,INF,sizeof(x))
#define   lowbit(x)   (x&-x)
#define   S(n)        scanf("%d",&n)
#define   P(n)        printf("%d ",n)
#define   PN(n)       printf("%d\n",n)
#define   FP(k)       freopen(k , "r" ,stdin)
#define   RPTI(s , n) for(int i=s;i<n;i++)
#define   RPTJ(s , n) for(int j=s;j<n;j++)
#define   RPTK(s , n) for(int k=s;k<n;k++)
#define   RPTL(s , n) for(int l=s;l<n;l++)
const LL     mod   = 1000000;
///const int    prime = 999983;
const int    INF   = 0x3f3f3f3f;
const int    INFF  = 1e9;
const double pi    = 3.141592653589793;
const double inf   = 1e18;
const double eps   = 1e-10;
inline int read_int(){
    int ret=0;
    char tmp;
    while(!isdigit(tmp=getchar()));
    do{
        ret=(ret<<3)+(ret<<1)+tmp-'0';
    }
    while(isdigit(tmp=getchar()));
    return ret;
}
/*******************************************/
typedef long long ll ;
const int moddd = 1e9+7 ;
int a[100005] ;
const int maxn = (1 << 20) ;
ll d[20][20] ;
ll t[maxn] ;
ll ji[maxn] ;
int bin[25] ;
const int wei = 20 ;
int main(){
    int jie = 1 ;
    for(int i=0;i<20;i++ , jie*=2){
        bin[i] =  jie ;
    }
    int n , m ;
    ///freopen("in.txt" , "r", stdin) ;
    int T ;scanf("%d" , &T) ;
    while(T --){
        for(int j=0;j<maxn;j++) ji[j] = inf ;
        mem0(t) ; mem0(d) ;
        scanf("%d" , &n) ;
        for(int i=0;i<n;i++) scanf("%d" , &a[i]) ;
        ll tot = 0 ;
        int maxx = 0 ;
        for(int i=0;i<20;i++){
            for(int j=0;j<n;j++){
                if(a[j] & bin[i]) {
                    maxx = i ;
                }
            }
        }
        for(int i=0;i<n-1;i++) {
            int t1 = a[i] ; int t2 = a[i+1] ;
            if(t1 > t2) swap(t1 , t2) ;
            tot += (t2 - t1) ;
            int tmp = t2 - t1 ;
            int ti = 0 ;
            for(int j=wei-1;j>=0;j--){
                bool b1 = t2 & bin[j] ; bool b2 = t1 & bin[j] ;
                if(b1 != b2) {
                    ti = j ;break ;
                }
            }
            for(int j=0;j<wei;j++){
                d[ti][j] += abs((t2^bin[j])-(t1^bin[j])) - tmp ;
            }
        }
        ll ans = tot ;
        ll mii = 0 ;
        ll counter = 0 ;
        int upper = (1 << (maxx)) ;
        for(int i=0;i<upper;i++) t[i] = tot ;
        for(int i=0;i<wei;i++){
            for(int x=0;x<upper;x++) ji[x] = inf ;
            for(int x=0;x<upper;x++){
                ll tmp = 0 ;
                int tx = x % (bin[i] << 1) ;
                if(ji[tx] != inf) {
                    t[x] += ji[tx] ; continue ;
                }
                else{
                    int flag = 0 ; if(x & bin[i]) flag = 1 , tmp += d[i][i] ;
                    for(int j=0;j<wei;j++){
                        ///counter ++ ;
                        if(x & bin[j]){
                            if(flag == 0) tmp += d[i][j] ;
                            else if(j < i) tmp -= d[i][j] ;
                        }
                    }
                    ji[tx] = tmp ; t[x] += tmp ;
                }
            }
        }
        for(int i=0;i<upper;i++){
            if(t[i] < ans) {
                ans = t[i] ; mii = i ;
            }
        }
        //cout << "counter = " << maxn <<" "<< counter << endl ;
        cout << mii << " " << ans << endl ;
    }
}