2007年百度之星程序设计大赛初赛试题与解答 第1场 大话西游与数字游戏

来源:互联网 发布:悉尼全年气温数据 编辑:程序博客网 时间:2024/06/15 18:41


/*题目描述:-----------------------------------------------------------------------------------------------*/

大话西游与数字游戏
“叉烧鸡翅膀,我呀最爱吃!……”
百度spider组的“黑龙潭之行”在烤着鸡翅,唱着星爷的经典时达到高潮。大家在篝火旁围成一圈,开始玩“数7”加强版游戏,规则如下:
规则1:遇7的倍数或含7的数时pass。
规则2:遇有包含相同数字的数时pass。注意相同数字不必相邻。例如121。
数错的惩罚很残酷——吞食烤全羊。为避免惩罚,百度工程师们需要你——史上最强程序员的帮助。百度工程师想知道:
req1 x:符合规则1的第x个数是什么?
req2 y:符合规则2的第y个数是什么?
req12 z:同时符合规则1、2的第z个数是什么?
query n:数n是规则1中的第几个数,是规则2中的第几个数?
输入格式
输入的每一行为一个查询,由一个查询词和一个无符号整型数组成。共有四种查询,查询词分别为req1、req2、req12、query(区分大小写)。
输出格式
前三种查询输出一个无符号整型的解。对于“query n”的查询,若n是规则中的数则输出相应的解,否则输出-1。
输入样例
req1 10
req2 10
req12 10
query 14
输出样例
11
10
12
-1 13

/*算法描述与分析-----------------------------------------------------------------------------------------------*/
前三个问题,采用动态规划法,先定位最高位,再依次从高位到低位,搜索每一位的数字,算法复杂度为O(K*logN),
K是常数,N为输入数字。第四个问题采用数字的二分查找,O(logN*lgN),前者以10为底,后者以2为底。每个问题的思路为:
1、问题1使用req1arr[10][10][7],req1arr[i][j][k]表示最高位为j的,长度为i(10进制)的正整数中,整除7余k的数有多少个。
时间复杂度O(70*logN),空间复杂度O(700)。
2、问题2不使用而外数组,只是为了提高效率将n!预先存入fac[n]。时间复杂度O(10*logN),空间复杂度O(1)。
3、问题3使用nums[10][11][7],digits[10][10][7],compose[1024][7],compose_digits[1024]。nums[i][j][k]表示最高位为j的,
长度为i的,满足规则2的,不含有7的数字中,整除7余k的数有多少个。digits[i][j][k]表示长度为i的,满足规则2的,不含有7的,
含有数字j的数有多少个。compose[i][k]表示,将i的二进制数中1对应的位数所组成的排列中,整除7余k的数有多少个。
compose_digits[i]表示i中有几个1。时间复杂度O(70000*logN*logN),空间复杂度O(7000)。
4、问题4使用数字的二分查找。left=0,right=N,然后计算(left+right)/2,直到找到,或left=right。

/*源代码-------------------------------------------------------------------------------------------------------*/
源代码中包括三块:1、本算法的源代码;2、另一种算法(逐一数)的源代码;3比较测试代码。
当数字较大时,本算法的优势明显。

#include <vector>
#include <string>
#include <iostream>
using namespace std;

#define tp 0

static const unsigned int ten[10]={1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
static const unsigned int fac[12]={1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800};
/*******************************************class define req*******************************/
class req{
protected:
    unsigned int highdigit, val_b, val_c, ret;
    virtual int init();
    virtual int dpinit()=0;
    virtual int dparray(unsigned int d)=0;
    virtual unsigned int searchdigit(unsigned int& value, unsigned int d)=0;
    virtual int test_print()=0;
public:
    unsigned int searchnumber(unsigned int value);
};

/*******************************************class define req1*******************************/
class req1:public req{
protected:
    unsigned int req1arr[10][10][7];
    int dpinit();
    int dparray(unsigned int d);
    unsigned int searchdigit(unsigned int& value, unsigned int d);
    int test_print(){return 1;}
public:
    req1();
};

/*******************************************class define req2*******************************/
class req2:public req{
protected:
    unsigned int digit;
    int init();
    int dpinit();
    int dparray(unsigned int d);
    unsigned int searchdigit(unsigned int& value, unsigned int d);
    int test_print(){return 1;}
public:
};

/*******************************************class define req12*******************************/
class req12:public req{
    unsigned int nums[10][11][7],digits[10][10][7],compose[1024][7],compose_digits[1024],digit;
    int init();
    int dpinit();
    int dparray(unsigned int d);
    unsigned int searchdigit(unsigned int& value, unsigned int d);
    int test_print();
public:
    req12();
};
/*******************************************class define query*******************************/
class query{
public:
    req1 *preq1;
    req2 *preq2;
    int searchnumber(unsigned int value);
};

/*******************************************class define baiduwest*******************************/

class baiduwest{
    req1 oreq1;
    req2 oreq2;
    req12 oreq12;
    query oquery;
public:
    baiduwest(){oquery.preq1=&oreq1;oquery.preq2=&oreq2;}
    int searchnumber(unsigned int value, unsigned int type);
};


/*******************************************class employ req*******************************/
int req::init(){
    highdigit=0;val_b=0;val_c=0;ret=0;
    return 1;
}

unsigned int req::searchnumber(unsigned int value){
    unsigned int i,j;
    //initial
    init();
    //search highest digit
    for(i=1;i<10;i++){
        dparray(i);
        if(searchdigit(value,i)!=10) break;
    }
    if(highdigit==0) return 0;
    //search from highest-1 digit
    for(i=highdigit-1;i>0;i--){
        dpinit();
        for(j=1;j<=i;j++)
            dparray(j);
        searchdigit(value,i);
    }
    return ret;
}

/*******************************************class employ req1*******************************/
req1::req1(){
    memset(req1arr, 0 ,sizeof(req1arr));
    req1arr[0][0][0]=1;
}

int req1::dpinit(){
    return 1;
}
int req1::dparray(unsigned int d){
    unsigned int j,k,t;

    for(j=0,t=0;j<7;j++)
        t+=req1arr[d][0][j];
    if(t) return 1;

    for(j=0;j<10;j++)
        for(k=0;k<7;k++)
        req1arr[d][0][k]+=req1arr[d-1][j][k];
    for(j=1;j<10;j++){
        if(j==7) continue;
        t=(j*ten[d-1])%7;
        for(k=0;k<7;k++){
            req1arr[d][j][(t+k)%7]+=req1arr[d][0][k];
        }
    }
    return 1;
}
unsigned int req1::searchdigit(unsigned int& value, unsigned int d){
    int j,k,t;
    t=ret%7;
    val_b=0;
    if(highdigit) j=0;
    else j=1;
    for(;j<10;j++){
        if (j==7) continue;
        for(k=0,val_c=0;k<7;k++)
            if((t+k)%7) val_c+=req1arr[d][j][k];
        if((val_b<value)&&(value<=val_b+val_c)){
            if(highdigit==0) highdigit=d;
            value-=val_b;
            ret+=j*ten[d-1];
            return j;
        }
        val_b+=val_c;
    }
    value-=val_b;
    return j;
}

/*******************************************class employ req2*******************************/
int req2::init(){
    req::init();
    digit=0;
    return 1;
}

int req2::dpinit(){
    return 1;
}

int req2::dparray(unsigned int d){
    return 1;
}
unsigned int req2::searchdigit(unsigned int& value, unsigned int d){
    unsigned int j,t;

    //cout<<"req2::searchdigit d:"<<d<<" value:"<<value<<endl;
    for(j=0,t=0;j<10;j++)
        if((digit&(1<<j))==0) t++;

    val_b=0;
    if(highdigit) j=0;
    else j=1;
    for(;j<10;j++){
        if(digit&(1<<j)) continue;
        val_c=(fac[t-1]/fac[t-d]);
        if((val_b<value)&&(value<=val_b+val_c)){
            if(highdigit==0) highdigit=d;
            value-=val_b;
            ret+=j*ten[d-1];
            digit|=1<<j;
            return j;
        }
        val_b+=val_c;
    }
    value-=val_b;
    return j;
}

/*******************************************class employ req12*******************************/
int req12::test_print(){
    unsigned int i,j,k;

    if(tp) return 1;

    for(i=0;i<10;i++){
        cout<<i<<":"<<endl;
        for(j=0;j<10;j++){
            cout<<j<<"(";
            for(k=0;k<7;k++)
                cout<<nums[i][j][k]<<",";
            cout<<")";cout<<endl;
        }

    }
    cout<<"digit:"<<digit<<" highdigit: "<<highdigit<<endl;

    return 1;
}

req12::req12(){
    memset(compose_digits,0,sizeof(compose_digits));
    unsigned int i,t,c;
    for(i=1;i<1024;i++){
        t=i;c=0;
        while(t){t&=t-1;c++;}
        compose_digits[i]=c;
    }
}

int req12::dpinit(){
    memset(nums,0,sizeof(nums));
    nums[0][10][0]=1;
    memset(digits,0,sizeof(digits));
    memset(compose,0,sizeof(compose));
    compose[0][0]=1;
    return 1;
}

int req12::init(){
    req::init();
    digit=1<<7;
    dpinit();
    return 1;
}
int req12::dparray(unsigned int d){
    unsigned int j,k,m,t,tm,t_sum[7];

    memset(t_sum,0,sizeof(t_sum));
    //computer nums[d][j][k]
    for(j=0;j<10;j++){
        if(digit&(1<<j)) continue;
        t=(j*ten[d-1])%7;
        for(k=0;k<7;k++){
            nums[d][j][(t+k)%7]+=nums[d-1][10][k];
            nums[d][j][(t+k)%7]-=digits[d-1][j][k];
        }
        for(k=0;k<7;k++)
            t_sum[k]+=nums[d][j][k];
    }
    //nums[d][10][k]
    for(k=0;k<7;k++)
        nums[d][10][k]=t_sum[k];
    //compose[]
    for(m=0;m<1024;m++){
        if(compose_digits[m]!=d-1) continue;
        for(j=0;j<10;j++){
            if((digit&(1<<j))||(m&(1<<j))) continue;
            tm=(1<<j)|m;
            t=(j*ten[d-1])%7;
            for(k=0;k<7;k++){
                compose[tm][(t+k)%7]+=compose[m][k];
            }
        }
    }
    //digits[d][j][k]
    for(m=0;m<1024;m++){
        if(compose_digits[m]!=d) continue;
        for(j=0;j<10;j++){
            if((digit&(1<<j))||!(m&(1<<j))) continue;
            for(k=0;k<7;k++)
                digits[d][j][k]+=compose[m][k];
        }
    }
    return 1;
}
unsigned int req12::searchdigit(unsigned int& value, unsigned int d){
    unsigned int j,k,t;
    t=ret%7;
    val_b=0;
    if(highdigit) j=0;
    else j=1;
    for(;j<10;j++){
        if(digit&(1<<j)) continue;
        for(k=0,val_c=0;k<7;k++)
            if((t+k)%7) val_c+=nums[d][j][k];
        if((val_b<value)&&(value<=val_b+val_c)){
            if(highdigit==0) highdigit=d;
            value-=val_b;
            ret+=j*ten[d-1];
            digit|=1<<j;
            return j;
        }
        val_b+=val_c;
    }
    value-=val_b;
    return j;
}

/*******************************************class employ query*******************************/

int query::searchnumber(unsigned int value){
    unsigned int i,obj=0,t;
    unsigned int left,right,now;
    int res[2];

    req* areq[2];
    areq[0]=preq1;
    areq[1]=preq2;

    res[0]=0;res[1]=0;
    if(!(value%7)) res[0]=-1;
    for(i=0;i<10;i++){
        if(value<ten[i]) break;
        t=(value/ten[i])%10;
        if(t==7) res[0]=-1;
        if ((1<<t)&obj) {res[1]=-1;break;}
        obj|=(1<<t);
    }

    for(int i=0;i<2;i++){
        if(res[i]==-1) continue;
        left=1;right=value;
        cout<<"query "<<i<<endl;
        while(left!=right){
            now=(left+right)>>1;
            t=areq[i]->searchnumber(now);
            if(t==value){res[i]=now;break;}
            else if(t==0){right=now-1;}
            else if(t<value)left=now+1;
            else right=now-1;
        }
        if(left==right) res[i]=left;

    }
    //cout<<"query ok"<<endl;
    cout<<res[0]<<" "<<res[1]<<endl;
    return 1;
}

/*******************************************class employ baiduwest*******************************/

int baiduwest::searchnumber(unsigned int value, unsigned int type){
    if(type==1){cout<<oreq1.searchnumber(value)<<endl;}
    if(type==2){cout<<oreq2.searchnumber(value)<<endl;}
    if(type==3){cout<<oreq12.searchnumber(value)<<endl;}
    if(type==4){oquery.searchnumber(value);}
    return 1;
}


/****************************************class test*****************************************/
bool IncludeOrModSevenu(unsigned int cinn){
    if(cinn==0) return false;
    if(cinn%7==0) return true;
    unsigned int temp;
    while (cinn){
        temp=cinn%10;
        if(temp==7) return true;
        cinn/=10;
    }
    return false;
}

bool HaveSameNumn(unsigned int cinn){
    unsigned int record[10];
    memset(record,0,sizeof(record));
    while(cinn){
        record[cinn%10]++;
        cinn/=10;
    }
    for(int i=0;i<10;i++)
        if(record[i]>1) return true;
    return false;
}

int baidustar20070104_test(int type, int value){
    int cinn,num,j=0;
    cinn=value;
    if (type==1){
        num=0; j=0;
        while(1){
            j++;
            if(!IncludeOrModSevenu(j)) num++;
            if(num==cinn){
                break;
            }
        }
    }
    if(type==2){
        num=0;j=0;
        while(1){
            j++;
            if(!HaveSameNumn(j)) num++;
            if(num==cinn){
                break;
            }
        }
    }
    if(type==3){
        num=0;j=0;
        while(1){
            j++;
            if((!HaveSameNumn(j))&&(!IncludeOrModSevenu(j))) num++;
            if(num==cinn){
                break;
            }
        }
    }
    if(type==4){
        num=0;j=0;
        if (IncludeOrModSevenu(cinn)) j=-1;
        else{
            while(1){
                j++;
                if(!IncludeOrModSevenu(j)){
                    num++;
                    if(j==cinn){
                        j=num;
                        break;
                    }
                }
            }
        }
    }
    if(type==5){
        num=0;j=0;
        if (HaveSameNumn(cinn)) j=-1;
        else{
            while(1){
                j++;
                if(!HaveSameNumn(j)){
                    num++;
                    if(j==cinn){
                        j=num;
                        break;
                    }
                }
            }
        }
    }
    return j;
}


/***************************************************************************/
int doit(){
    baiduwest* a=new baiduwest();
    int value[]={109,1342,53214,230000,-1};
    int i;
    for(i=0;i<20;i++){
        if(value[i]==-1) break;
        cout<<"i: "<<i<<" value:"<<value[i]<<endl;
        a->searchnumber(value[i],3);
        cout<<"test: "<<baidustar20070104_test(3,value[i])<<endl;
        cout<<endl;
    }
    return 1;
}

原创粉丝点击