训练赛7(小)

导语

涉及的知识点

思维,数学,贪心,随机化

链接:ACM2019weekly3

题目

A( HDU 6235)

题目大意:给出一个数n,定义这样一个排列:该排列共有n个数,1~n每个数各出现一次,并且 p i %   ∣ p i − p i − 2 ∣ p_i\%\ |p_i-p_{i-2}| pi% pipi2为0,求出一个满足条件的序列

思路:使 p i − p i − 2 p_i-p_{i-2} pipi2为1即可

代码

#include <bits/stdc++.h>

using namespace std;
int n,T,data[121212];
int main() {
    scanf("%d",&T);
    while(T--) {
        scanf("%d",&n);
        int j=1;
        for(int i=1; i<=n; i+=2,j++)
            data[i]=j;
        for(int i=2; i<=n; i+=2,j++)
            data[i]=j;
        for(int i=1; i<=n; i++)
            printf("%d%c",data[i],i==n?'\n':' ');
    }
    return 0;
}

B(HDU 6237)

题目大意:给出n堆石子,每堆有 a i a_i ai个,每次操作可以将一个石子在堆之间移动,求最少的操作次数使得存在一个x, a i a_i ai%x=0

思路:首先,x必为总石子数的因数(因为x可以被每一项整除),那么用总石子数的每个质因子来进行尝试即可,对于每个质因数,求出每堆石子需要拿走多少才能被整除,累和需要拿走/缺少的个数,并记录,将这些个数升序排序,因为要求操作数最小,所以采取用小补大的策略,即将拿走/缺少个数小的堆来补对应个数大的堆

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;//必须开long long
ll N,T,a[121212],fac[121212],t[121212];//存石头数,存因子,存余数
int main() {
    scanf("%lld",&T);
    while(T--) {
        scanf("%lld",&N);
        ll sum=0,len=0,ans=1e10;//ans必须很大
        for(ll i=1; i<=N; i++) {
            scanf("%lld",&a[i]);
            sum+=a[i];
        }
        sort(a+1,a+N+1);
        for(ll i=2; i<=sum/i; i++)//取质因子
            if(sum%i==0) {
                while(sum%i==0)
                    sum/=i;
                fac[len++]=i;
            }
        if(sum>1)//自己就是质因子
            fac[len++]=sum;
        for(ll i=0; i<len; i++) {
            ll x=fac[i],res=0,total=0;//尝试每个质因子
            for(ll j=1; j<=N; j++) {
                t[j]=a[j]%x;//获取余数
                total+=t[j];
            }
            sort(t+1,t+1+N);
            for(ll j=N; j>=1; j--)
                if(total>0) {
                    res+=x-t[j];//补成能整除,用小数补大数
                    total-=x;
                }
            ans=min(ans,res);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

C(HDU 6242)

题目大意:给出N个点,找到一个圆,至少有一半的点在圆上,保证有解

思路:3点确定一个圆,每次随机选取三个点确定一个圆,再判断圆是否可行,因为至少一半点在圆上,所以大多数点都在一个圆上,因此随机次数较少,N不足5时需要特判

代码

#include <bits/stdc++.h>
using namespace std;
int T,N;
struct point {
    double x,y;
} P[212121];
double dis(point a,point b) {
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
point solve(point a,point b,point c) {//三点共圆圆心公式
    double x=( (a.x*a.x-b.x*b.x+a.y*a.y-b.y*b.y)*(a.y-c.y)-(a.x*a.x-c.x*c.x+a.y*a.y-c.y*c.y)*(a.y-b.y) ) 
    / (2*(a.y-c.y)*(a.x-b.x)-2*(a.y-b.y)*(a.x-c.x));
    double y=( (a.x*a.x-b.x*b.x+a.y*a.y-b.y*b.y)*(a.x-c.x)-(a.x*a.x-c.x*c.x+a.y*a.y-c.y*c.y)*(a.x-b.x) ) 
    / (2*(a.y-b.y)*(a.x-c.x)-2*(a.y-c.y)*(a.x-b.x));
    return (point) {
        x,y
    };
}
int main() {
    scanf("%d",&T);
    while(T--) {
        scanf("%d",&N);
        for(int i=0; i<N; i++)
            scanf("%lf%lf",&P[i].x,&P[i].y);
        if(N==1||N==2) {//只有一两个点
            printf("%lf %lf %lf\n",P[0].x+1,P[0].y,1.0);
            continue;
        }
        if(N==3||N==4) {//只有三四个点
            printf("%lf %lf %lf\n",(P[1].x+P[2].x)/2,(P[1].y+P[2].y)/2,dis(P[1],P[2])/2);
            continue;
        }
        while(1) {
            int a=rand()%N;
            int b=rand()%N;
            int c=rand()%N;//抽三个点出来
            int sum=0;
            if(a==b||b==c||a==c)
                continue;
            if(fabs((P[b].y-P[a].y)*(P[c].x-P[b].x)-(P[c].y-P[b].y)*(P[b].x-P[a].x))<=1e-6)
                continue;
            point q=solve(P[a],P[b],P[c]);//求圆心
            for(int i=0; i<N; i++)//判断有多少点在圆上
                if(fabs(dis(P[i],q)-dis(P[a],q))<=1e-6)
                    sum++;
            if(2*sum>=N) {
                printf("%lf %lf %lf\n",q.x,q.y,dis(P[a],q));
                break;
            }
        }
    }
    return 0;
}

D(HDU 6243)

题目大意:n条狗,n个笼子,每个狗有编号对应有编号的笼子,现在随机打乱,求有多少只狗不在对应编号的期望

思路:总方案有n!种,对于每条狗,不在对应编号的方案有n!-(n-1)!种,对于每条狗来说概率相等,可以直接拿方案数替代频数,则每条狗的概率为 n ! − ( n − 1 ) ! n ! \frac{n!-(n-1)!}{n!} n!n!(n1)!,最后×n得到期望数

代码

#include <bits/stdc++.h>

using namespace std;
int T,N;
int main() {
    scanf("%d",&T);
    for(int i=1; i<=T; i++) {
        scanf("%d",&N);
        printf("Case #%d: %.10f\n",i,N-1.0);
    }
    return 0;
}

E(HDU 6247)

题目大意:有N场比赛,每场比赛需要 a i a_i ai个板子,以防万一,每次比赛要做准备10%的板子(向上取整),询问总共需要多少板子

思路:直接模拟

代码

#include <bits/stdc++.h>
using namespace std;
int T;
int main() {
    scanf("%d",&T);
    for(int i=1; i<=T; i++) {
        printf("Case #%d: ",i);
        int N,ans=0;
        scanf("%d",&N);
        while(N--) {
            int t;
            scanf("%d",&t);
            ans+=(t+9)/10+t;
        }
        printf("%d\n",ans);
    }
    return 0;
}

F(HDU 6253)

题目大意:有一个无限大的棋盘,正中心摆了一个马,马走日,给出一个数N,输出N步之后有多少个位置马可能已经走过了

思路:思路较复杂,具体参考文章后的参考文献,注意开unsigned long long

代码

#include <bits/stdc++.h>
using namespace std;
int T,data[5]= {1,9,41,109,205};
int main() {
    scanf("%d",&T);
    for(int i=1; i<=T; i++) {
        unsigned long long N;
        scanf("%d",&N);
        printf("Case #%d: ",i);
        if(N<5)
            printf("%d\n",data[N]);
        else
            cout <<14*N*N-6*N+5<<endl;

    }
    return 0;
}

G(HDU 6245)

题目大意:两个人打羽毛球,获胜的条件是11:9或者平均的时候比到有一方多两分为止,A赢B需要付出X元,B赢A需要付出Y元,B可以决定输赢,一开始B没有钱且B不能赊账,询问B最多能赢几局

思路:X≤Y,则B需要输一整局攒钱,否则可以输赢交替获胜每一局

代码

#include <bits/stdc++.h>
using namespace std;
int T;
int main() {
    scanf("%d",&T);
    for(int i=1; i<=T; i++) {
        int X,Y,K,ans=0;
        scanf("%d%d%d",&X,&Y,&K);
        if(X>Y)//如果输了得的钱比赢的输的钱多,则每局都可以赢
            ans=K;
        else//否则以0:11比分输掉一局来攒钱
            ans=11*X*K/(2*X+11*Y);
        printf("Case #%d: %d\n",i,ans);
    }
    return 0;
}

参考文献

  1. HDU-6235 Permutation
  2. hdu 6243,6247
  3. hdu6245 Rich Game
  4. 在下头很铁之HDU-6253
  5. hdu 6237
  6. HDU 6242
  7. 求三点共圆求圆心半径及其推导(三角形外心)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值