暑假集训第一弹

暑假集训第一弹

A:POJ 4311  Meeting point-1

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4311

题意:给定n个点的坐标,然后让你找出其中一个点到其他所有点的距离和最小,并输出这个距离。

    (只能横着走和竖着走)

输入:先输入1个T,然后是T组数组,每组数据 先是一个n 然后n个点。

输出:距离。

 

思路:

  因为直接爆搜是n^2的,数据范围是1e5

  所以 先对x排序,然后把每个点与x0的距离存下来,然后再对y排序,同理。

  最后扫一遍数组。

  // ans=(x1+x2+x3+...+xn)-n*xi+(y1+y2+...+yn)-n*yi;

  // 表述能力过差 直接写一个公式,最后不断更新ans即可

 

代码:

#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
using namespace std;
 
typedef struct{
    long long x,y;
    int k;
}point;

bool cmpx(point a,point b)
{
    if(a.x==b.x)
        return a.y<b.y;
    return a.x<b.x;
}

bool cmpy(point a,point b)
{
    if(a.y==b.y)
        return a.x<b.x;
    return a.y<b.y;
}

long long xx[100100],yy[100100];
long long sumx[100100],sumy[100100];
point a[100100];

int main()
{
//    freopen("a.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(xx,0,sizeof xx);
        memset(yy,0,sizeof yy);
        memset(sumx,0,sizeof sumx);
        memset(sumy,0,sizeof sumy);
        
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%lld %lld",&a[i].x,&a[i].y);
        sort(a,a+n,cmpx);
        a[0].k=0;
        for(int i=1;i<n;i++)
        {
            xx[i]=a[i].x-a[0].x;
            sumx[i]=sumx[i-1]+xx[i];
            a[i].k=i;
        }
        sort(a,a+n,cmpy);
        for(int i=1;i<n;i++)
        {
            yy[i]=a[i].y-a[0].y;
            sumy[i]=sumy[i-1]+yy[i];
        }
        long long ans=sumx[n-1]+sumy[n-1];
        for(int i=1;i<n;i++)
        {
            long long now=0;
            now += ( a[i].k*xx[a[i].k]-sumx[a[i].k-1] );                        // x 左
            now += ( sumx[n-1]-(n-a[i].k-1)*xx[a[i].k]-sumx[a[i].k] );            // x 右
            now += ( i*yy[i]-sumy[i-1] );                                        // y 下 
            now += ( sumy[n-1]-(n-i-1)*yy[i]-sumy[i] );                            // y 上

            if(now<ans)        ans=now;
        }
        printf("%lld\n",ans);
    }
}
View Code

 

———————————————————分————割————线———————————————————

 

B:ACdream 1187  Rational Number Tree

传送门:http://acdream.info/problem?pid=1187

题意:有一棵二叉树根是 1/1,左儿子是  父亲的分子/父亲的分子+分母 右儿子是 父亲的分子+分母/父亲的分母

    两个操作 给个位置 问你分数 ; 给个分数 问你位置

输入:一个n 然后n个操作

输出:Case #n:分子 分母(或者位置) 

       这里的数据会很大 所以要 llu

 

思路:

  简单的二叉树递归。

代码:

#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm> 
using namespace std;

int t;
unsigned long long pp,qq;

void solve1(unsigned long long n)
{
    pp=qq=1;
    if(n==1)    return;
    
    int x[100], tot=0;
    while(n)
    {
        x[++tot]=n%2;
        n=n/2;
    }
    
    for(int i=tot-1;i;i--)
    {
        if(x[i])    pp=pp+qq;
        else        qq=pp+qq;
    }
}

unsigned long long solve2(unsigned long long p,unsigned long long q)
{
    if(p==1 && q==1)    return 1;
    
    int dep=0, x[100];
    
    while(p != 1 || q != 1)
    {
        dep++;
        if(p>q)                    //
        {
            p=p-q;
            x[dep]=1;
        }
        else                    //
        {
            q=q-p;;
            x[dep]=0;
        }
    }
    unsigned long long ans=1;
    for(int i=dep;i;i--)        // 从下往上*2 
    {
        ans=ans<<1;
        if(x[i])    ans++;
    }
    
    return ans;
}

int main()
{
    int T;
    scanf("%d",&T);
    for(t=1;t<=T;t++)
    {
        int type;
        scanf("%d",&type);
        if(type&1)
        {
            unsigned long long n;
            scanf("%llu",&n);
            solve1(n);
            printf("Case #%d: %llu %llu\n",t,pp,qq);
        }
        else
        {
            unsigned long long x,y;
            scanf("%llu %llu",&x,&y);
            printf("Case #%d: %llu\n",t,solve2(x,y));
        }
    }
}
View Code

 

———————————————————分————割————线———————————————————

 

C:并不会做 // 留坑

 

———————————————————分————割————线———————————————————

 

D:CodeForces 266C  Below the Diagonal

传送门:http://codeforces.com/problemset/problem/266/C

题意:给你一个n*n的矩阵并且其中有n-1个位置是1(其他位置是0)

每次可以交换其中任意两行或者两列,把所有的1都交换到对角线以下(横坐标大于纵坐标)

输出详细操作

输入:一个n,表示矩阵的宽,然后n-1行有n-1个位置表示那里是1

输出:每行一个操作

 

思路:

  类似线代的上三角矩阵。

  因为 n-1 个 1 所以 存在某一列没有1,我们把它最后一列,然后找到一个有1的换到最后一行

  这样相当于变成了一个新的矩阵(去掉最后一行和最后一列)  n-1的宽 n-2的点 循环直到n=0;

 

代码:

#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm> 
using namespace std;

typedef struct{
    int p,x,y;
}way;

way ans[10010];
int tot=0,a[1005][1005];

void solve(int n)
{
    int sh=0;
    for(int i=1;i<=n;i++)
        if(a[i][n])
            sh=1;
    if(sh)
    {
        for(int i=1;i<n;i++)
        {
            int flag=1;
            for(int j=1;j<=n;j++)
                if(a[j][i])
                    flag=0;
            if(flag)
            {
                for(int j=1;j<=n;j++)
                    swap(a[j][i],a[j][n]);
                ans[tot].p=2;
                ans[tot].x=i;
                ans[tot].y=n;
                tot++;
                break;
            }
        }
    }
    sh=1;
    for(int i=1;i<n;i++)
        if(a[n][i])
            sh=0;
    if(sh)
    {
        for(int i=1;i<n;i++)
        {
            int flag=0;
            for(int j=1;j<n;j++)
                if(a[i][j])
                    flag=1;
            if(flag)
            {
                for(int j=1;j<=n;j++)
                    swap(a[i][j],a[n][j]);
                ans[tot].p=1;
                ans[tot].x=i;
                ans[tot].y=n;
                tot++;
                break;
            }
        }
    }
    if(n>1)
        solve(n-1);
}

int main()
{
    int n;
    scanf("%d",&n);
    memset(a,0,sizeof a);
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d %d",&x,&y);
        a[x][y]=1;
    }
    solve(n);
    printf("%d\n",tot);
    for(int i=0;i<tot;i++)
        printf("%d %d %d\n",ans[i].p,ans[i].x,ans[i].y);
}
View Code

 

———————————————————分————割————线———————————————————

 

E:并不会做 // 留坑

 

———————————————————分————割————线———————————————————

 

F:CodeForces 680A   Bear and Five Cards  (水)

传送门:http://codeforces.com/problemset/problem/680/A

题意:给你5个数字,重复的数字可以去掉,但是最多去掉3个且只能去掉一个数字,问你和的最小值。

输入:5个数字

输出:最小的和

 

思路:

  因为数字最大是100 所以开个 数组存每个数字的个数(超过3的定为3)。

  然后扫一遍 把重复的最大值maxx保存下来,

  输出sum-maxx

 

代码:

#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm> 

int a[100];

int main()
{
    memset(a,0,sizeof a);
    int sum=0,isum=0,x;
    for(int i=1;i<=5;i++)
    {
        scanf("%d",&x);
        a[x]++;
        if(a[x]>3)    a[x]--;
        sum += x;
    } 
    for(int i=1;i<=100;i++)
        if(a[i]>1)
            isum=a[i]*i<isum?isum:a[i]*i;
    printf("%d\n",sum-isum);    
}
View Code

 

 

转载于:https://www.cnblogs.com/Lostsm/p/5711936.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值