CF #125 Edu(A ~ D)

CF Edu125 Div.2

A - Integer Moves(思维)

Description:

​ 给定一个坐标x y 从0 0开始走 每次走的欧几里得距离必须是整数 问几步能到

Solution

​ 0 0到0 0 0步

​ 如果是直角三角形 就可以一步到

​ 如果不是直角三角形 那就先走一步横再走一步竖 两步到

Code:

void solve()
{
	int x, y;
	cin >> x >> y;
	if(x == 0 && y == 0)	{cout << 0 << endl; return;}
	if((int)sqrt(x * x + y * y) * (int)sqrt(x * x + y * y) == x * x + y * y)
		cout << 1 << endl;
	else 
		cout << 2 << endl;
}

B - XY Sequence(贪心)

Description:

​ 给定n b x y 要求构造出一个长度为n+1 和最大的序列

​ 构造规则 序列首位为0 下一位可以选择前一位+x 或者 -y 但是不能大于b

Solution

​ 贪心 +x小于等于b就加 不行就-y

​ 证明的话 我们可以想到 只对第一个能+x的地方-y 后面正常操作 那么折线将会整体低一节 那还是加+x比较合适

Code:

void solve()
{
	LL n, b, x, y;
	cin >> n >> b >> x >> y;
	LL res = 0, cur = 0;
	for(int i = 0; i < n; i++)
	{
		if(cur + x <= b)	cur += x, res += cur;
		else cur -= y, res += cur;
	}
	cout << res << '\n';
}

C - Bracket Sequence Deletion(读题 + 分类讨论)

Description:

​ 操作

​ 每次操作选择一个最短好前缀并将其删去

​ 定义一个好前缀

​ 该前缀是一个合法的括号序列 eg () (()) ((())())

​ 或者该前缀是一个长度大于等于2的回文串

​ 你可以进行任意次操作直到序列中不存在好前缀为止

​ 输出操作次数和剩下的序列的长度

Solution

​ 分类讨论

用指针l表示当前序列的首位 用l的前进 来等价于 删去前缀
当前为'('的时候 后面无论是')'或者'('	这都是一个最短前缀 所以l无脑加2即可
当前为')'的时候 找下一个')'  因为"))"或者")(()"  得出无论 两个)中间夹着多少个( 都是回文串 
什么时候终止呢 当且仅当 当前为)且找不到下一个)时终止

Code:

void solve()
{
	int n;
	string s;
	cin >> n >> s;
	int l = 0, cnt = 0;
	while(l + 1 < n)
	{
	    if(s[l] == '(' || (s[l] == ')' && s[l + 1] == ')'))
	        l += 2;
	    else //s[l] == ')'
	    {
	        int r = l + 1;
	        while(r < n && s[r] != ')')    r ++;
	        if(r == n)  break;
	        l = r + 1;
	    }
	    cnt ++;
	}
	cout << cnt << ' ' << n - l << endl;
}

D - For Gamers. By Gamers.(预处理 + 二分)

Description:

​ 给定n个单位 和 C个金币

​ 然后你会得到各个单位的费用c_i和攻防属性d_i h_i

​ 以及下面的怪物攻防属性 D H

​ 有m个怪物 你只能雇佣n个同一单位去击杀怪物 保证每一个单位都存活的情况下杀掉怪物

​ 求杀掉每个怪物的最小花费 若金币不够的话就输出-1

Solution

​ 先要推一下式子 什么叫保证每一个单位都存活的情况下杀掉怪物

​ 原句为

Thus, Monocarp wins the battle if and only if his squad kills the monster strictly faster than the monster kills one of his units. The time is compared with no rounding.
翻译: 因此,当且仅当他的小队杀死怪物的速度严格快于怪物杀死他的一个单位时,Monocarp才会赢得这场战斗。时间的比较是没有四舍五入的(double)

如果存在多个单位的话 可以交替抗伤害 所以我们试一下推公式

怪物杀单位的时间 h/D  	单位杀怪物的时间 H/d
当且仅当 h/D > H/d成立时 能够赢
设我们放了x个单位 那么(h/D > H/d*x)   x > HD / hd ==> x = floor(HD/hd) + 1;
cost = x*c_i	
好的 思路整理出来了 那我们可以做到的是 对于每个怪物枚举一遍每种单位打怪的花费 取最小花费
这样就是n * m 铁铁超时
那从哪里优化呢 想一想有哪些参数 1单位2怪物3花费 那么不能枚举12 那就枚举32试试
预处理出1~C的每个花费得到的最大战斗属性 然后对每个怪物进行二分查找 找出第一个刚好杀掉怪物的花费
如果找不到 那就证明花费爆了

Code:

LL f[N];
 
int main()
{
    int n, C;
    scanf("%d%d", &n, &C);
    for(int i = 1; i <= n; i++)
    {
        LL c, d, h;
        scanf("%lld%lld%lld", &c, &d, &h);
        f[c] = max(f[c], d * h); 
        //爆了c个金币 得到一个单位 为了防止同样费用的单位 取max
    }
 
    for(int i = 1; i <= C; i++)
    {
        if(f[i])
        {
            for(int j = i; j <= C; j += i) //枚举i的倍数j
                f[j] = max(f[j], f[i] * j / i); //状态转移 爆j个金币 得到j / i个单位
        }
    }
 
    for(int i = 1; i <= C; i++) f[i] = max(f[i], f[i - 1]); 
    //得到当前金币数能得到的最强的战斗属性
    int m;
    scanf("%d", &m);
    while(m --)
    {
        LL x, y;
        scanf("%lld%lld", &x, &y);
        x *= y;
        
        LL l = 1, r = C; 
        while(l < r)
        {
            int mid = l + r >> 1;
            if(f[mid] > x)  r = mid;
            else l = mid + 1;
        }
        if(f[l] > x)    printf("%lld ", l); 
        //二分出刚好可以打过这个怪物的最小花费 也就是第一个大于怪物属性的单位
        else printf("-1 ");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值