[Offer收割]编程练习赛49

A.相似颜色
每两位枚举一下0~15,更新一下就好了。。

#include <bits/stdc++.h>
#define FOR(i,a,b)  for(int i=(a);i<(b);i++)
#define REP(i,a,b)  for(int i=(a);i<=(b);i++)
#define DOWN(i,a,b) for(int i=(a);i>=(b);i--)
#define CLR(a)      memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

const double eps=1e-8;
const int INF=0x3f3f3f3f;
const ll LL_INf=0x3f3f3f3f3f3f3f3f;
const int N=100000+10;
const int mod=1e8+7;

int tran(char c){
    if ('0'<=c&&c<='9') return c-'0';
    else return c-'a'+10;
}

int encode(char a,char b){
    return 16*tran(a)+tran(b);
}

char decode(int a){
    if (a>=0&&a<=9) return a+'0';
    else return a-10+'a';
}

string s;
int num[3];

int main(){
    cin>>s;
    cout<<'#';
    num[0]=encode(s[1],s[2]);
    num[1]=encode(s[3],s[4]);
    num[2]=encode(s[5],s[6]);
    // FOR(i,0,3) cout<<num[i]<<' '<<endl;
    FOR(i,0,3){
        int big=INF;
        int k;
        for(int j=0;j<=15;j++){
            int tmp=16*j+j;
            if ((tmp-num[i])*(tmp-num[i])<big){
                big=(tmp-num[i])*(tmp-num[i]);
                k=tmp;
            }
        }
        // cout<<"k="<<k<<endl;
        cout<<decode(k%16);
    }
}

B.挑选子集
如果知道剩余系的概念,这题应该就秒了。。

#include <bits/stdc++.h>
#define FOR(i,a,b)  for(int i=(a);i<(b);i++)
#define REP(i,a,b)  for(int i=(a);i<=(b);i++)
#define DOWN(i,a,b) for(int i=(a);i>=(b);i--)
#define CLR(a)      memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

const double eps=1e-8;
const int INF=0x3f3f3f3f;
const ll LL_INf=0x3f3f3f3f3f3f3f3f;
const ll mod=1000000009;
const int N=1000+10;

int n,m,k,num;
ll c[N][N],a[N],b[N],ans;

int main(){
    c[0][0]=1;
    REP(i,1,100){
        c[i][0]=1;
        REP(j,1,i){
            c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
        }
    }
    cin>>n>>m>>k;
    FOR(i,0,n) cin>>b[i];
    // n=unique(b,b+n)-b;
    FOR(i,0,n) {
        a[b[i]%k]++;
    }
    REP(i,0,k-1) ans=(ans+c[ a[i] ][m])%mod;
    cout<<ans<<endl;
}

C.矩阵迷宫
动态规划,用dp[i][j][k][0]和dp[i][j][k][1]表示,到(i,j)格改变了k次移动方向分别方向为向右和向下时所需支付的最小代价
唯一的坑点就是,由于2的幂很大,所以k不能枚举到n,也并不需要枚举到n,枚举20就差不多了,因为可以保证,只用改变一次方向并且只用200*100代价就能到终点。。很多人因为这个只有30分

#include <bits/stdc++.h>
#define FOR(i,a,b)  for(int i=(a);i<(b);i++)
#define REP(i,a,b)  for(int i=(a);i<=(b);i++)
#define DOWN(i,a,b) for(int i=(a);i>=(b);i--)
#define CLR(a)      memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

const double eps=1e-8;
const int INF=0x3f3f3f3f;
const ll LL_INF=0x3f3f3f3f3f3f3f3f;
const int mod=1e8+7;
const int N=100+10;

ll dp[N][N][N][2];
int n,a[N][N];
ll ans;

int main(){
    cin>>n;
    REP(i,1,n){
        REP(j,1,n){
            cin>>a[i][j];
        }
    }
    memset(dp,0x3f,sizeof(dp));
    dp[1][1][0][0]=a[1][1];
    dp[1][1][0][1]=a[1][1];
    REP(i,1,n){
        REP(j,1,n){
            if (i==1&&j==1) continue;
            REP(k,0,15){
                dp[i][j][k][0]=min(dp[i][j-1][k][0]+a[i][j],dp[i][j][k][0]);
                if (k) dp[i][j][k][0]=min(dp[i-1][j][k-1][1]+(1<<k-1)+a[i][j],dp[i][j][k][0]);


                dp[i][j][k][1]=min(dp[i-1][j][k][1]+a[i][j],dp[i][j][k][1]);
                if (k) dp[i][j][k][1]=min(dp[i][j-1][k-1][0]+(1<<k-1)+a[i][j],dp[i][j][k][1]);



            }
        }
    }
    // REP(k,0,2*n){
    // REP(i,1,n){
    //  REP(j,1,n){
    //      cout<<dp[i][j][k][0]<<'/'<<dp[i][j][k][1]<<' ';
    //      }
    //      cout<<endl;
    // }
    // cout<<endl;
    // }

    ans=LL_INF;
    REP(k,0,15){
        REP(i,0,1){
            ans=min(ans,dp[n][n][k][i]);
        }
    }
    cout<<ans<<endl;
    return 0;
}

D.第K小先序遍历
比赛时,由于放在第四题,很多人(我)以为很难,其实并不是很难。。这题有Catalan的背景,给出一个n个点的二叉树的中序遍历,求有多少颗不相同的树,答案就是Catalan树,知道这个之后,感觉一下,先对元素大小排序,通过k,知道第一个数是哪一位,然后不断分成两棵树,分治下去就好了。。

#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define CLR(a) memset(a,0,sizeof(a))
#define FOR(i,a,b)  for(int i=(a);i<(b);i++)
#define REP(i,a,b)  for(int i=(a);i<=(b);i++)
#define DOWN(i,a,b) for(int i=(a);i>=(b);i--)
#define DBG(x) cout<<"x"<<'='<<x<<endl;
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

const double eps=1e-8;
const int INF=0x3f3f3f3f;
const ll LL_INf=0x3f3f3f3f3f3f3f3f;
const ll mod=1000000009;
const int N=30+10;

int n,k,a[N];
vector<int> ans;
ll T[N];

void solve(int l,int r,ll k){
    // cout<<"l="<<l<<" r="<<r<<" k="<<k<<endl;

    if (l>r) return;

    vector< pair<int,ll> > p;
    REP(i,l,r) p.push_back( make_pair(a[i],i) );
    sort(p.begin(),p.end());

    // FOR(i,0,p.size()) cout<<p[i].second<<' ';
    // cout<<endl;

    int pos;
    FOR(i,0,p.size()){
        pos=p[i].second;
        ll num=T[pos-l]*T[r-pos];
        if (k-num<=0) {
            ans.push_back(p[i].first);
            break;
        }
        k-=num;
    }
    ll k1=(k-1)/T[r-pos]+1;
    ll k2=(k-1)%T[r-pos]+1;
    solve(l,pos-1,k1);
    solve(pos+1,r,k2);
}


int main(){
    cin>>n>>k;
    REP(i,1,n) cin>>a[i];
    T[0]=T[1]=1;
    REP(i,2,n){
        REP(j,0,i-1){
            T[i]+=T[j]*T[i-1-j];
        }
    }

    solve(1,n,k);
    FOR(i,0,n) cout<<ans[i]<<endl;

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值