[Atcoder Regular Contest94]

D: worst case

题目大意:给定 a,b a , b 求最大可能的 xy<ab x ∗ y < a ∗ b 的二元组 (x,y) ( x , y ) 的对数,前提是对于这些二元组,每个 x x 或每个y只可以出现一次
思路:这个题目是真的考思维啊,后面问了xsc大佬才算稍微搞懂了正解的做法,其实也是很结论的。我们先统计 xy x ≤ y 的二元组(x,y)的对数,最后再乘二就可以了,不难发现,如果要求最大的对数的话,那么对于每一个 x x 都是成立的,又因为xy,所以x的上限是 d=ab d = ⌊ a b ⌋ ,我们既而设 ans=2d1 a n s = 2 ∗ d − 1 ,减一是因为要减去 (a,b) ( a , b ) ,但是有几种特殊情况是要考虑的:1.当 d(d1)>=ab d ∗ ( d − 1 ) >= a b 时,很明显,在 d d 这个点满足条件的点对不是(d,d+1)而是 (d,d) ( d , d ) 所以这里的贡献是不可以算两次的,当出现这种情况的时候, ans a n s 需要减一。2.当 ab a b 本身是完全平方数的时候,由于我们求的是严格小于 ab a b 的对数,所以 d d d2的时候也是不满足情况的,所以又需要减一,这时需要注意 a a 是否等于b,若等于,由于前面已经减过了,所以刚才的减一是没有必要的。
看代码也许更好理解

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
void File(){
    freopen("ARC94D.in","r",stdin);
    freopen("ARC94D.out","w",stdout);
}
#define REP(i,a,b) for(register int i=a;i<=b;++i)
#define DREP(i,a,b) for(register int i=a;i>=b;--i)
#define MREP(i,x) for(register int i=beg[x];i;i=E[i].last)
#define ll long long
int n;
int main(){
    File();
    scanf("%d",&n);
    REP(i,1,n){
        ll a,b;
        scanf("%lld%lld",&a,&b);
        ll d=sqrt(a*b),ans=d*2-1;
        if(d*(d+1)>=a*b)ans--;
        if(d*d==a*b && a!=b)ans--;
        cout<<ans<<endl;
    }   
    return 0;
}

E: Tozan and Gezan

题目大意:两个人玩游戏,对于A和B两个序列,每个序列的元素和相等,甲每次选A中的一个正数减一,乙每次选B中的一个正数减一,直到两个序列完全相同的时候游戏结束,而甲希望游戏能够进行的更加地长,乙则相反,求在最优的情况下甲可以进行的游戏轮数
思路:由于元素和相等,不难发现,最后的状态就是A序列只剩一个非零元素,而甲不得不去选择它,当乙选择完其他的元素的时候刚好甲不得不选择的元素等于了B序列中对应的那个元素,所以甲希望B中那个元素最小,所以答案即为 sumAminB s u m A − m i n B

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
void File(){
    freopen("ARC94E.in","r",stdin);
    freopen("ARC94E.out","w",stdout);
}
#define REP(i,a,b) for(register int i=a;i<=b;++i)
#define DREP(i,a,b) for(register int i=a;i>=b;--i)
#define MREP(i,x) for(register int i=beg[x];i;i=E[i].last)
#define ll long long
int n;
ll ans,c=0x3f3f3f3f;
bool flag=1;
int main(){
    File();
    scanf("%d",&n);
    REP(i,1,n){
        ll a,b;
        scanf("%lld%lld",&a,&b);
        ans+=a;
        if(a>b && b<c)c=b;
        if(a!=b)flag=0;
    }
    if(flag){
        cout<<0<<endl;
        return 0;
    }
    cout<<ans-c<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值