2014 BUPT 新生排位赛04

A  大家一起点外卖

链接:http://code.bupt.edu.cn/problem/p/437/

思路:水题,注意负数的情况,注意long long 就能过了。

code:

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#define INF 100000005
#define eps 1e-9
using namespace std;
 
const int MAX_N=500005;
const int MAX_M=2000005;
 
int a[MAX_N],n,m;
int ma,mb;
int used[MAX_M],flag;
 
int abc(int a)
{
    if(a<0) return -a;
    return a;
}
void solve()
{
    flag=false;
    ma=0;
    mb=INF;
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
        used[a[i]]++;
    }
    for(int i=0;i<n;i++){
        if(m-a[i]<0) continue;
        if(!used[m-a[i]]) continue;
        if(m-a[i]==a[i]&&used[a[i]]<2) continue;
        if((mb-ma)>(abc(m-a[i]-a[i]))){
            mb=max(m-a[i],a[i]);
            ma=min(m-a[i],a[i]);
            flag=true;
        }
    }
    if(flag==false){
        printf("Sad\n");
        return ;
    }
    printf("%d %d\n",ma,mb);
    return ;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        memset(used,0,sizeof(used));
        solve();
    }
    return 0;
}

B 田田的公司

链接:http://code.bupt.edu.cn/problem/p/438/

思路:裸的并查集,比赛时候没有注意到long long 到最后也没过。

code:

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#define INF 100000005
#define eps 1e-9
using namespace std;
 
const int MAX_N=100005;
const int MAX_M=2000005;
 
int par[MAX_N];
int high[MAX_N];
long long  value[MAX_N];
 
void init(int n)
{
    for(int i=0;i<=n;i++){
        par[i]=i;
        value[i]=0;
    }
}
int Find(int x)
{
    if(par[x]==x) return x;
    else return par[x]=Find(par[x]);
}
void unite(int x,int y)
{
    x=Find(x);
    y=Find(y);
    if(x==y) return ;
    if(value[x]<value[y]){
        par[x]=y;
        value[y]+=value[x];
    }
    else{
        par[y]=x;
        value[x]+=value[y];
    }
}
bool same(int x,int y)
{
    return Find(x)==Find(y);
}
 
int main()
{
    int T,n,m,tt,a,b;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        init(n);
        for(int i=1;i<=n;i++) scanf("%lld",&value[i]);
        while(m--){
            scanf("%d",&tt);
            if(tt==1){
                scanf("%d%d",&a,&b);
                unite(a,b);
            }
            if(tt==2){
                scanf("%d",&a);
                printf("%lld\n",value[Find(a)]);
            }
        }
    }
    return 0;
}

C 崔逗逗的难题

链接:http://code.bupt.edu.cn/problem/p/439/

思路:公式都能推出来但是这道题题目卡精度,我的其他同学都能用double水过去,我无论换什么姿势用double都水不过去。

未ac code:

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#define INF 100000005
#define eps 1e-9
//#define Pi 3.1415926536
using namespace std;
 
const int MAX_N=100005;
const int MAX_M=2000005;
const int p=90000;
const double Pi=acos(-1.0);
 
int main()
{
    double r;
    while(~scanf("%lf",&r)){
        double s1=(Pi/3.0+1-sqrt(3.0))*(r*r);
        double s2=4.0*((Pi/12.0-1+sqrt(3.0)/2.0)*(r*r));
        double s3=4.0*(r*r-(Pi/6.0)*(r*r)-(sqrt(3.0)/4.0)*(r*r));
        printf("%.6lf %.6lf %.6lf\n",(Pi/3.0+1.0-sqrt(3.0))*r*r,4.0*((Pi/12.0-1.0+sqrt(3.0)/2.0)*r*r),4.0*(1.0-Pi/6.0-sqrt(3.0)/4.0)*r*r);
    }
    return 0;
}

崔逗逗给你信心

链接:http://code.bupt.edu.cn/problem/p/435/

思路: 我感觉这是一道比较好的题,多个步骤换换相扣。

(1)根据式子x^(2x)^(3x)可得,x^2x=3x     =>    x^2x=x+2x。2乘以x相当于将x二进制表示的最高位上加1的位置上放一个1,所以想要使等式成立就必须,x的二进制表示不能有相邻的1,因为如果有相邻的1,则做加法的时候高位上会产生一个1,而异或的话原来是1的位置将全部变成零。

(2)根据第一步的结论,我们需要做的就是判断小于n的数中有多少个相邻位置上不含一的数。我们以a[n]表示1~n位的二进制数中有多少相邻位上没有一的数。可以得到一个斐波那契数列就是 a[n]=a[n-1]+a[n-2]。预处理出这个数列再将每个带待求的n处理成二进制 ,从最高位向最低位扫,对于每个二进制位为1的位i,如果其后面的位也是一就可以则res+=a[i]跳出;如果后面的位是0则res+=a[i-1],再继续判断其他位。

(3) 其中还有很多的细节地方,赛后我也是改了好久才过了这道题。

code:

#include <iostream>
#include <cstring>
#include <cstdlib>
#include<cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#define INF 999999999
#define eps 1e-9
using namespace std;
 
const int MAX_M=200;
const int MAX_N=100005;
const int p=1000000009;
 
int a[100];
int bit[100];
int convert(long long n,int tt[])
{
    long long d=1;
    int cnt=0;
    while(d<=n) d=d*2,cnt++;
    d/=2;
    for(int i=cnt;i>=1;i--){
        tt[i]=n/d;
        n%=d;
        d/=2;
    }
    return cnt;
}
int main()
{
    a[0]=1;
    a[1]=2;
    for(int i=2;i<=100;i++) a[i]=(a[i-1]+a[i-2])%p;
    long long  x;
    int l,res;
    bool flag=0;
    while(~scanf("%lld",&x)){
        bit[0]=res=flag=0;
        l=convert(x,bit);
        for(int i=l;i>=2;i--){
            if(bit[i]&&bit[i-1]){
                res=(res+a[i]-1)%p;
                flag=1;
                break;
            }
            if(bit[i]) res=(res+a[i-1])%p;
        }
        if(bit[1]&&!flag) res++;
        if(x==1) res++;
        else res++;
        printf("%d\n",res);
    }
}

E 焦级长搭积木

链接:http://code.bupt.edu.cn/problem/p/434/

思路:用dp的方法可以很快的求出来总步数,dp[i][j][k]=dp[i-k][j-1][k-1]+dp[i-k][j-1][k+1]  其中dp[i][j][k] 表示一个i个积木搭成j层最底层k个的总数量。

之后就是求第k个排序,在这个地方卡了一下一直想不到比较好的方法,去看了一下菊苣们的题解知道了,就是对于每个位置判断k和dp[n][h][m]的关系,前dp[n-m][h-1][m-1] 种序列对应的操作室将上一次层的数量-1,第dp[n-m][h-1][m-1]+1到dp[n-m][h-1][m+1]种序列对应的操作是上一层的数量+1,这样我们不断的更新跟新就能更新出第k种序列了。

code:

#include <iostream>
#include <cstring>
#include <cstdlib>
#include<cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#define INF -1000000000
#define eps 1e-9
using namespace std;
 
const int MAX_N=545;
const int MAX_H=65;
const int MAX_M=20;
 
long long dp[MAX_N][MAX_H][MAX_M];
int N,M,H;
long long nn;
 
void solve()
{
    memset(dp,0,sizeof(dp));
    for(int i=1;i<=N;i++){
       if(i<=10) dp[i][1][i]=1;
        for(int j=2;j<=H;j++){
            for(int k=1;k<=10;k++)
                if(k<=i) dp[i][j][k]=dp[i-k][j-1][k-1]+dp[i-k][j-1][k+1];
        }
    }
    printf("%lld\n",dp[N][H][M]);
}
void output(int N,int H,int M,long long k)
{
    int a[H+1];
    int n=N,h=H,m=M;
    a[0]=m;
    for(int i=1;i<H;i++){
        if(k<=dp[n-m][h-1][m-1]){
            a[i]=m-1;
            n=n-m;
            h--;
            m--;
        }
        else{
            k-=dp[n-m][h-1][m-1];
            a[i]=m+1;
            n=n-m;
            h--;
            m++;
        }
    }
    for(int i=0;i<H;i++){
        printf("%d",a[i]);
        if(i!=H-1) printf(" ");
    }
    printf("\n");
}
int main()
{
    while(~scanf("%d%d%d",&N,&H,&M)){
        solve();
        cin>>nn;
        while(nn!=-1){
            output(N,H,M,nn);
            cin>>nn;
        }
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值