1. 程式人生 > >HDU5573 2015 上海 B題(模擬-找規律)

HDU5573 2015 上海 B題(模擬-找規律)

/////// 2016.10.12

之前做有思路,時隔兩個月再做,思路都找不到了只是覺得題目有些熟,看來還是對這種解題思維沒有深入理解和學習,重溫。

而且發現了幾個點,之前確實考慮的不周全:

①構造題一定有明顯的地方告訴你一些資料上的限制規律,比如本題N<2^k<2^60,所以才考慮從由1 2 4 8...2^n這一條路上的數字下手,而不僅僅是因為二進位制可以表示任何數,否則無法解決走k層全部為加,之和卻還是小於N的情況。

②用cout輸出足夠大的數時,會自動用科學計數法,從而導致WA,最好的改善方法,就是直接用printf("%lld %c");

③注意迴圈變數i如果需要和N比較的話,那麼i也應該用Longlong,另外pow()函式,要在前面加long long 做一個強制型別轉換,printf("%lld %c",(long long)pow(...) );

④之前寫的程式碼可讀性太差了。重新在下面附上一份,重點在選擇哪些數為正哪些數為負時,其實只需將要減去的數由下到上遍歷一遍,如果之前所算的要減去的數(指 差/2)大於目前節點的數,那麼目前節點輸出負號,要減去的數減去目前節點的數之後繼續往上遍歷即可。因為同樣的道理,差/2 也是可以由這一條路上的數字的某個組合組成。

///////2016.08.10

0

題目很簡單

1

思路分析:

因為是special判題,所以不止一種可能。

其次,關鍵在於這樣一句:N<2^k<2^60,所以如果每層選中的點要麼加 要麼不加也不減,那麼N一定可以由1 2 4 8...2^n這一條路上的數字組成(類似二進位制可以表示任何數)

再考慮如果有減,就相當於將這裡一條路上的數字都加起來然後選擇其中部分數為減,使得最終結果等於N。

考慮n1 2 4 8 ... 2^相加之和,減去路上的某一個數就相當於總和減去這個數兩遍,那麼減去的數之和為之前相差的一半即可,最後多減的1使得2^n這個數為2^n+1即可

以10 4為例子,1 2 4 8 ,之和為15,15-10=5,也就是說減去5的一半,(因為題目要求非加即減,那麼減去任意一個數,都相當於所有數的和減去該數兩遍),而5%2==1時,不是偶數,我們將5+1=6,6/2=3,從前面的數總共減去3即可,而多減去的1,用最後一位8+1=9來彌補即可抵消。

以 9 4為例,1 2 4 8,之和為15,15-9=6,是偶數,所以6/2=3,直接從前面減去得數之和為3即可。(注意,前面的數,總是2的x次方)

做的時候,思路是有的但是不是特別清晰,另外模擬題還是考驗編碼能力。

2

之前的程式碼:

#include <iostream>
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <algorithm>
using namespace std;

long long int n;
int k;
int cou;
long long int a[65];
int ttt=0;
int Find(int rr){
    int i=1;
    int flagg=0;
    while(i<=rr){
        if(i==rr){
            flagg=1;
        }
        i*=2;
    }
    return flagg;
}
int main(){
    int kase;
    cin>>kase;
    for(int kk=1;kk<=kase;kk++){
        cou=0;
        ttt=0;
        scanf("%lld%d",&n,&k);
        long long int zh=1;
        long long int gg=1;
        for(int i=2;i<=k;i++){
            zh+=(gg*2);
            gg=gg*2;
        }
        long long int yu=zh-n;
        printf("Case #%d:\n",kk);
        if(yu==0){
            for(int i=1;i<=zh;i=i*2){
                cout<<i<<" "<<"+"<<endl;
            }
        }
        else{
            if(yu%2==1){
                yu++;
                ttt=1;
                yu/=2;
            }
            else{
                yu/=2;
            }
            while(!Find(yu)){
                int hh=0;
                int i=1;
                while(hh==0){
                if(i>yu){
                    i/=2;
                    a[cou++]=i;
                    yu=yu-i;
                    hh=1;
                }
                i*=2;
                }
            }
            a[cou++]=yu;
            int pp=1;
            for(int l=1;l<=k;l++,pp=pp*2){
                if(ttt==1&&l==k){
                    pp+=1;
                }
                if(cou>=0&&pp==a[cou-1]){
                    cou--;
                    cout<<a[cou]<<" "<<"-"<<endl;
                }
                else{
                    cout<<pp<<" "<<"+"<<endl;
                }
            }
        }
    }
}


之後的程式碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<list>
#include<stack>
#include<iomanip>
#include<cmath>
#include<bitset>
#define memset(ss,b) memset((ss),(b),sizeof(ss))
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef long double ld;
#define INF (1ll<<60)-1
#define Max 1e9
using namespace std;
int k;
int n;
int t;
char a[70];
int flag=0;
ll num[65];
int main(){
    scanf("%d",&t);
    int tt=1;
    num[0]=1;
    num[1]=2;
    for(int i=2;i<=60;i++){
        num[i]=2*num[i-1];//放在外面先算一遍
    }
    while(t--){
        scanf("%d%d",&n,&k);
        printf("Case #%d:\n",tt++);
        memset(a,0);
        ll sum=0;
        ll yushu=0;//注意用long long
        for(int i=0;i<k;i++){
            sum+=num[i];
        }
        yushu=sum-n;
        int ji=0;//需要補償+1的標誌
        if(yushu%2==0){
            yushu/=2;
        }
        else if(yushu%2==1){
            yushu+=1;
            yushu/=2;
            ji=1;
        }
        for(int i=k;i>=1;i--){
            if(yushu>=num[i-1]){
                yushu-=num[i-1];
                a[i]='-';
            }
            else{
                a[i]='+';
            }
        }
        for(int i=1;i<k;i++){
            printf("%lld %c\n",num[i-1],a[i]);
        }
        if(ji) printf("%lld %c\n",num[k-1]+1,a[k]);
        else printf("%lld %c\n",num[k-1],a[k]);
    }

    return 0;
}