2020河南省CCPC A、C、E、I题解


题目链接: 2020年河南省CCPC大学生程序设计竞赛

A、班委竞选

在这里插入图片描述

#include<iostream>
using namespace std;
const int N = 55;
int a[N][N];
int n,m;

int main()
{
    cin >> n >> m;
    int cnt = 1;
    while(n--)
    {
        int c,t;
        cin >> c >> t;
        a[c][cnt++] = t;
    }
    
    for(int i=1; i<=m; i++)
    {
        int Max = 0,Maxi = 0;
         for(int j=1; j<cnt; j++)
        {
            if(Max < a[i][j])
            {
                Max = a[i][j];
                Maxi = j;
            }
        }
        cout << Maxi << " ";
    }
       return 0;
}

C、我得重新集结部队

在这里插入图片描述
注意用 long long

#include<iostream>
#include<cmath>
using namespace std;

typedef long long LL;

struct node
{
    int type; //狂躁者2 异虫1
    LL x,y;
    LL h;
    LL atk;
    LL r;
    int liu; //0留在战场,2死亡
}aa[3000];

LL dist(int x1,int y1,int x2,int y2)
{
    return ((LL)(x1-x2)*(x1-x2)+(LL)(y1-y2)*(y1-y2));
}

int main()
{
    int n;
    cin >> n;
    int cnt = -1;
    while(n--)
    {
        cnt++;
        int t;
        cin >> t;
        if(t == 1) //异虫
        {
            aa[cnt].type = 1;
            cin >> aa[cnt].x >> aa[cnt].y >> aa[cnt].h;
        }
        else //狂躁者
        {
            aa[cnt].type = 2;
            cin >> aa[cnt].x >> aa[cnt].y >> aa[cnt].atk >> aa[cnt].r;
            LL Min = 1e18;
            int Mini = -1;
            for(int i=0; i<=cnt; i++)
            {
                if(aa[i].type==1 && aa[i].h>0)
                {    
                    LL d = dist(aa[i].x,aa[i].y,aa[cnt].x,aa[cnt].y);
                    if(d < Min )
                    {
                        Min = d;
                        Mini = i; //最近的异虫
                    }
                }
            }
            if(Mini == -1) continue;
            aa[cnt].x = aa[Mini].x,aa[cnt].y = aa[Mini].y; //跳到最近的异虫位置
         
            for(int i=0; i<=cnt; i++)
            {
                if(aa[i].type==1 && aa[i].h>0 && dist(aa[cnt].x,aa[cnt].y,aa[i].x,aa[i].y)<=aa[cnt].r*aa[cnt].r)
                {
                    aa[i].h -= 3*aa[cnt].atk; //攻击异虫
                    if(aa[i].h>0) //狂躁者离开战场
                    {
                        aa[cnt].liu = 2;
                    }
                    else //异虫死亡
                    {
                         aa[i].h = 0;
                    }
                }
            }
        }
    }
    for(int i=0; i<=cnt; i++)
    {
        if(aa[i].type==1) //chong
        {
            if(aa[i].h>0) cout << "Yes" << endl;
            else cout << "No" << endl;
        }
        else  //kuang
        {
            if(aa[i].liu==2) cout<<"No"<<endl;
            else cout << "Yes"<<endl;
        }
    }
    return 0;
}

E、发通知

在这里插入图片描述
当一个区间是 [l,r] 时,经过 l 时,可以接到通知的人数+1,到 r + 1点时,这个同学不能接到通知了,可以接到通知的人数-1。所以,一个区间内我们只需要考虑两个点 :l 和 r + 1。当到 l 时,我们异或w,人数+1,当到 r+1 时,我们再异或w,人数-1。

为什么到 r+1 时还要异或w?
因为异或的性质 :A ^ w ^ w = A,当到 r+1 时,我们需要把之前在 l 点异或的 w 给撤销掉(也就是恢复到异或前),所以在 r+1 点再异或w就行了。
初始:A
l点:A ^ w
r+1点:A ^ w ^ w = A

#include<iostream>
#include<map>
using namespace std;
typedef pair<int,int> PII;
map<int,PII> m; //端点:{w,人数}
int n,k;

void add(int x,int w,int cnt)
{
        m[x].first ^= w;
        m[x].second += cnt;
}

int main()
{
    cin >> n >> k;
    while(n--)
    {
        int l,r,w;
        cin >> l >> r >> w; //左端点、右端点、愉悦度
        add(l,w,1); //l点能收到通知的人数+1
        add(r+1,w,-1); //r+1这个点已经出l~r的区间了,人数-1
    }
    
    int res = -1,num = 0,t = 0;
    for(auto x:m)
    {
        t ^= x.second.first;
        num += x.second.second;
        if(num >= k)
            res = max(res,t);
    }
    cout << res;
}

I、太阳轰炸

在这里插入图片描述
在这里插入图片描述
击中碎片的概率 p = ( R   1   + r ) 2 R   2   2 \frac {(R~1~+r) ^2} {R~2~ ^2} R 2 2(R 1 +r)2,未击中的概率为 q = R   2   2 − ( R   1   + r ) 2 R   2   2 \frac {R~2~^2-(R~1~+r)^2} {R~2~ ^2} R 2 2R 2 2(R 1 +r)2

若想摧毁碎片,那么击中的次数至少为 k = ⌈ h a \frac {h} {a} ah

摧毁碎片的概率 x = C(n,k) * pk * q n-k + C(n,k+1) * pk+1 * qn-k-1 + … + C(n,n) * pn * q0 ,x符合二项分布。

注意:( A b \frac {A} {b} bA) % mod = A * b’ % mod (b’指b的逆元 求逆元:快速幂求逆元)
求组合数:使用博客内求组合数II方法求解
注意使用long long

#include<iostream>
using namespace std;

typedef long long LL;
LL n,r1,r2,r,a,h;
const int p = 1e9 + 7,N = 5e6 + 5;
LL fact[N],infact[N];

LL qmi(LL a,int k)//快速幂
{
    a = a % p;
    LL res = 1;
    while(k)
    {
        if(k&1) res = res * a % p;
        a = a * a % p;
        k >>= 1;
    }
    return res;
}

LL C(int a,int b)
{
	return fact[a] * infact[b] % p * infact[a-b] % p;
}

int main()
{
   // cin >> n >> r1 >> r2 >> r >> a >> h;
    scanf("%lld%lld%lld%lld%lld%lld",&n,&r1,&r2,&r,&a,&h);
    int k;
    if(h%a == 0)
        k = h/a;
    else k = h/a + 1; //上取整
    
    if(k>n) //k最大到n,>n时不可能,概率为0
    {
    	cout<<"0";
    	return 0;
	}
	
	if(r1+r>=r2) //概率最大为1
    {
        cout<<"1";
        return 0;
    }
    
    fact[0] = infact[0] = 1;  
	for(int i=1; i<=n; i++) //预处理出阶乘、阶乘的逆元
	{
	   fact[i] = (LL)fact[i-1] * i % p; 
	   infact[i] = (LL)infact[i-1] * qmi(i,p-2) % p;	
	}  
    
    LL res = 0;
    LL rn = qmi(r2 * r2 % p,p-2); //r2的逆元
    LL pp = (r1+r)*(r1+r) % p * rn % p; //即概率p
    LL qq = (r2*r2%p - (r1+r)*(r1+r)%p + p) % p * rn % p;//即概率q
    
    LL pk  = qmi(pp,k); //p^k
    LL qnk = qmi(qq,n-k); //q^(n-k)
    
    for(int i=k; i<=n; i++)
    {
        res = (res + (C(n,i) * pk % p * qnk % p) % p) % p;
        pk = pk * pp % p;
        qnk = qnk * qmi(qq,p-2) % p;
    }
    
    printf("%lld",res);
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值