iwtgm-22

题目链接

A.

怪物先承受攻击,若承受住了,再回血,没承受住则死亡
也就是说若我们这一轮不能把它完全杀死,就要选择让它回血最少的攻击
若这一轮最大的攻击力能把它杀死则不用关心回血
若不能一招致死且回血大于攻击,那么怪物永远不会被杀死

void solve() {
    int n,x;cin>>n>>x;
    int ma=-inf,tack=-inf;
    for(int i=0,d,h;i<n;i++){
        cin>>d>>h;
        ma=max(ma,d);
        tack=max(tack,d-h);
    }
    if(ma>=x){
        cout<<1<<endl;return ;
    }
    if(x>ma&&tack<=0){
        cout<<-1<<endl;return ;
    }
    x-=ma;
    int ans=ceil(x*1.0/tack);
    ans++;
    cout<<ans<<endl;
}

B.

gcd(𝑎,𝑚)=gcd(𝑎+𝑥,𝑚)
辗转相除法:gcd(a+x,m)=gcd((a+x)modm,m)
0<=x<m,0<=(a+x)%m<m
设(a+x)%m为y
gcd(a,m)=gcd(y,m)=d
欧拉函数可以求在一定范围内与一个数互质的数的个数
所以我们两遍除以d
得到gcd( y/d,m/d)=1
也就是求比m/d小且与m/d互质的数的个数

int gcd(int a, int b) {
    return b > 0 ? gcd(b, a % b) : a;
}
ll eula(ll n){
    ll ans=n;
    for(ll i=2;i*i<=n;i++){
        if(n%i==0){//质因数
            while(n%i==0)n/=i;//质因数的最大幂次
            ans=ans/i*(i-1);//φ(n)=n*(1-1/p1)*(1-1/p2)*……*(1-1/pn),把括号内的通分,先除分母再乘分子
        }
    }
    if(n>1)ans=ans/n*(n-1);//特判当n是质数时,不经过上面的for循环,贡献是(n-1)
    return ans;
}
 
void solve() {
    ll a,m;cin>>a>>m;
    cout<<eula(m/gcd(a,m))<<endl;
}

C.

推箱子问题
负数部分取正后一样的处理方式,正负分开即可
把最后的状态划分为两个部分:
第一部分是前面连续的一段箱子,第二部分是后面的各个箱子都在原来的位置
我们去枚举连续箱子的长度即可

代码有注释:

int n,m,a[N],b[N],same[N],box_bef[N];
vector<int>pa,na,pb,nb;
int work(vector<int> box,vector<int>pos){
    int sz1=box.size(),sz2=pos.size();
    for(int i=0,j=0;j<sz2;j++){
        same[j]=0;
        while(i<sz1&&box[i]<=pos[j]){
            if(box[i]==pos[j])same[j]=1;//箱子的初始位置就是特殊位置
            ++i;
        }
        box_bef[j]=i;//当前特殊位置及之前有几个箱子
        if(j)same[j]+=same[j-1];//预处理前缀和
    }
    int ans=same[sz2-1],add=0;
    for(int i=0,j=0;i<sz2;i++){
        while(j<sz2&&pos[j]<pos[i]-box_bef[i]+1)j++;//pos[i]是连续箱子的结尾,pos[j]得在连续箱子的起点或起点之后(防止多算了特殊位置)
        int sz=i-j+1;//箱子覆盖的特殊位置的个数
        add=max(add,sz-same[i]);//same[i]及之前的初始位置在特殊位置的,要么被连续箱子部分算过贡献了,要么箱子被后移了(没有贡献了)所以减去
    }
    return ans+add;
}
void solve() {
    cin>>n>>m;
    na.clear();pa.clear();nb.clear();pb.clear();
    for(int i=1;i<=n;i++){
        cin>>a[i];//箱子的位置
        if(a[i]>0)pa.push_back(a[i]);//正负分开
        else na.push_back(-a[i]);//正负分开
    }
    for(int i=1;i<=m;i++){
        cin>>b[i];//特殊位置的位置
        if(b[i]>0)pb.push_back(b[i]);//正负分开
        else nb.push_back(-b[i]);//正负分开
    }
    reverse(na.begin(),na.end());//按从小到大的顺序给的,转化成正数后需要倒置
    reverse(nb.begin(),nb.end());
    cout<<work(pa,pb)+work(na,nb)<<endl;
}
posted @ 2023-11-13 20:13  WW爆米花  阅读(3)  评论(0编辑  收藏  举报