EOJ Monthly 2019.9 题解

C题

本题是个思维暴力题

因为受到的伤害是固定的,所以问题不在于哪个时机 Cuber QQ 打出最后一击,而是是否能在每次外界攻击前配合之前的攻击打死小兵,我们只需要在这次攻击结算前一秒打出最后一击就行了。

而要求第一下最晚,就恰好是从 ansai1 (也就是这次攻击结算前一秒) 恰好一直连续攻击 x 次配合外界攻击击杀小兵,显然这样是可行的又是最好的方案。注意需要过滤掉超过 108 的攻击,或者干脆加一个时间为 108+1,伤害为 n 的攻击。

然后就是从小到大枚举每次攻击前一秒,看看是否可以给出最后一击,然后更新答案。注意时间可能相等,需要一次处理完所有 ai 相同的攻击,也要注意随之而来的爆 int 问题。

本题坑点有如下(我全踩了,怒wa3小时):

1.注意精度问题

2.注意删除大于1e8的时间,我做错的原因是,直接把第一个存进去了,忘记第一个也可能是大于1e8,不过一般人应该不会跟我的傻做法一样

3.计算时间时,应该用时间-(总血量-1)/战斗力*冷却时间,因为如果血量和战斗力相同,在最后一秒就行。

4.注意要对相同时间的攻击叠加处理,并且如果所有攻击用完还有血量,直接从1e8往前减就行

5.因为我是按照题解写的,并根据wa点数据找到自己的漏洞,所以我的代码并不精简,应当进行优化,然而这题写了3个小时,就懒得优化了

#include<cstring>
#include<string>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
#include<cstdio>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int N=1e6+10;
const ll mod=1e9+7;
int a[N],b[N];
ll c[N],d[N];
int main(){
    ll res=-1;
    ll n,m,t,s;
    cin>>n>>m>>s>>t;
    int i;
    for(i=1;i<=m;i++){
        scanf("%d%d",&a[i],&b[i]);
    }
    int cnt=0;
    if(a[1]<=1e8){
    cnt++;
    c[1]=a[1];
    d[1]=b[1];
    }
    for(i=2;i<=m;i++){
        if(a[i]>1e8)
        continue;
        while(a[i]==c[cnt]){
            d[cnt]+=b[i];
            i++;
        }
        if(i>m)
        break;
        cnt++;
        c[cnt]=a[i];
        d[cnt]=b[i];
    }
    for(i=1;i<=cnt;i++){
        ll tmp=c[i]-1;
        if(tmp<t){
            tmp+=t;
            if(tmp/t*s>=n)
            res=c[i]-1;
        }
        else{
        if(tmp/t*s>=n){
            res=tmp-(n-1)/s*t;
        }}
        n-=d[i];
        if(n<=0)
        break;
    }

    if(i>cnt){
        res=1e8-(n-1)/s*t;
        if(res<0)
        res=-1;
    }
    cout<<res<<endl;
}
 
View Code

 

D题

我们只关心鸭子是否分布在一个半圆中,所以鸭子离圆心的距离不重要。我们可以假设鸭子都落在圆周上。

如果所有的鸭子分布在同一个半圆中,那么让鸭子面朝圆心,所有的鸭子一定都在某一只鸭子的右手边。

令所有鸭子都在第 i 只鸭子的右手边是事件 Pi,则 Pi 发生的概率是 2^1n。那么,n 只鸭子分布在其中任何一只鸭子的右手边的概率是不是 n2^1n

答案是肯定的。可以证明 PiPj (ij) 不会同时发生(因为 n 只鸭子不会同时分布在 ij 的右手边,如果 ij 的右手边,j 就一定在 i 的左手边)。对于 n 个不会同时发生的事件,它们之中任何一个发生的的概率就是每一个发生的概率之和,也就是说,n 只鸭子分布在其中任何一只鸭子的右手边的概率是 n2^1n

因此,n 只鸭子分布在同一个半圆中的概率就是 n2^1n

另外本题有很多注意点:

1.用快速幂求逆元,因为p是素数

2.对输入的n需要提前%p,防止爆long long

3.一个小知识点,虽然题目要求是要最简真分数,但是我们直接求逆元并mod就可以得出正确答案。

4.做幂运算时,调用库函数会爆long long,因此要用快速幂求。

#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<map>
#include<vector>
#include<cstdio>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int N=110;
const ll mod=1e9+7;
ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}
ll qmi(ll m,ll k){
    ll res=1%mod;
    ll t=m%mod;
    while(k){
        if(k&1){
            res=res*t%mod;
        }
        t=t*t%mod;
        k>>=1;
    }
    return res%mod;
}
int main(){
    ll n;
    int t;
    cin>>t;
    ll res=0;
    while(t--){
        cin>>n;
        if(n<=2)
          res=1;
        else{
            ll tmp=qmi(2,n-1);
            n%=mod;
            res=n*qmi(tmp,mod-2)%mod;
        }
        cout<<res<<endl;
        
        
    }
}
 
View Code
posted @ 2020-01-17 10:19  朝暮不思  阅读(261)  评论(1编辑  收藏  举报