AtCoder Beginner Contest 174

A - Air Conditioner

代码

signed main()
{
    int x;
    cin >> x;
    if(x >= 30) cout << "Yes" << endl;
    else cout << "No" << endl;
}

B - Distance

分析

题意:给一堆点,问到原点距离在k以内的点的个数。
思路:a * a + b * b <= k * k 不开根号,避免丢失精度。

代码

#include <bits/stdc++.h>
#include <sstream>
using namespace std;
#define endl "\n"
#define int long long

signed main()
{
    int n, d, cnt = 0;
    cin >> n >> d;
    d = d * d;
    for(int i = 1; i <= n; i ++)
    {
        int a, b;
        cin >> a >> b;
        if(a * a + b * b <= d) cnt ++;
    }
    cout << cnt << endl;
}

C - Repsept

分析

题意:给你一个k,问你7,77,777,7777…中是否有一个数是k的倍数,如果有,输出这个数的位数,否则输出-1。

思路:大数取余。模拟除法得到余数的过程,让777…的位数每次增加一位,然后除以k,如果除尽,输出这个数的位数,否则输出-1。

借一张图:
在这里插入图片描述

https://blog.csdn.net/qq_43690454/article/details/108859923

代码

#include <iostream>
using namespace std;
const int N = 1e6+1000;
int mod;

int main(void)
{
	cin >> mod;
  	int f = 0, sum = 0, ans = 0;
  	for(int i = 0; i < N; i ++)
    {
        sum = (sum * 10 + 7) % mod;
        if(sum % mod == 0)
        {
            f = 1, ans = i; 
            break;
        }
    }
    if(f) cout << ans + 1 << endl;
    else cout << -1 << endl;
    return 0;
}

D - Alter Altar

分析

思维 or 双指针

题意:给定字符串s s只包括两种字符’R’和’W’ 'W’不能出现在’R’的左边

很**的,想了好久都没整出来(因为懒得模拟,懒得动手,得改 )。

思路1:统计字符串中R的个数,记为cntR,可以推断最终结果一定是“RRRWWWW”的样子,所以只需要将区间[1,cntR]中的W和R交换就行,因此答案就是[1,cntR]中W的个数。大佬的思路,妙不可言。

代码1

#include <bits/stdc++.h>
using namespace std;
char a[200010];
int posw[200010], posr[200010];
int main()
{
    int n;
    cin >> n;
    cin >> (a+1);
    int cntr = 0;
    for(int i = 1; i <= n; i ++)
    {
        if(a[i] == 'R') cntr ++;
    }
    int ans = 0;
    for(int i = 1; i <= cntr; i ++)
    {
        if(a[i] == 'W') ans ++;
    }
    cout << ans << endl;
}

思路2:其实就是一个双指针,从两端开始把右边出现的R和左边出现的W交换即可。

代码2

#include <bits/stdc++.h>

using namespace std;
char a[200010];
int posw[200010], posr[200010];
int main()
{
    int n;
    cin >> n;

    int cntw = 0, cntr = 0;

    for(int i = 1; i <= n; i ++)
    {
        cin >> a[i];
        if(a[i] == 'W') posw[cntw++] = i;
        else posr[cntr++] = i;
    }
    int ans = 0;
    int l = 1, r = n;
    while (l < r)
    {
        while(a[l] == 'R') l ++;
        while(a[r] == 'W') r --;
        if(l < r) swap(a[l], a[r]),ans ++;
    }
    
    cout << ans << endl;
}

E - Logs

分析

简单二分

题意:N个圆木,问切最多K次,最小的最大值是什么,题眼最小的最大值或者最大的最小值通常都是二分。

思路:最多砍K刀,并且保证每个原木最大长度为mid,如果K次可以实现把每一根原木都控制在<=mid,那么这个方案就是可行的。

代码

#include <bits/stdc++.h>

using namespace std;
#define ll long long
const int N = 2e5+10;
ll a[N];
ll n, k;

bool check(ll mid)
{
    ll kk = k;
    // 一共K刀, 保证mid是最大值
    for(int i = 1; i <= n; i ++)
    {
        if(a[i] <= mid) continue;
        kk -= ceil(a[i]/mid);
        if(kk < 0) break;
    }
    if(kk >= 0) return true;
    else return false;
}
signed main()
{
    cin >> n >> k;
    for(int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    // 排不排序都行
    sort(a+1,a+1+n);
    // 左边界为0会RE,比如l=0,r=1,l+r>>1=0,check函数中0不能做分母
    // ll l = 0, r = a[n]; 
    ll l = 1, r = a[n];
    while (l < r)
    {
        ll mid = (l + r) / 2;
        if(check(mid)) r = mid;
        else l = mid + 1;
    }
    cout << l << endl;
}

F - Range Set Query

分析

树状数组+离线处理

题意:给n个颜色,询问L~R区间内出现了几种颜色。

例如 1 3 6 3 1 2, [2, 4] 出现的颜色有3 6 1,共三种染色,答案为3

思路:(很简单耐心看完)这题可以使用可持久化线段树,代码太多了不考虑了。使用树状数组就是求前缀和,那么问题来了: 如何求前缀和的时候不重复计算多次出现的颜色,保证重复的颜色贡献只有1?
我的做法是开pos数组记录这个颜色上一次出现的位置,每次有重复颜色时,就把上一次出现的颜色的贡献清零,只计算最后一次出现的颜色的贡献。但这时候需要保证需要离线处理询问,将其按右端点R排序,每一次查询的时候,重复元素的贡献值不会出现在右端点R的右边。
再使用一个额外的pos数组记录上一次出现的重复颜色的下标就行,使用树状数组将上一次重复出现的位置-1,最新的位置+1,query函数得到的前缀和一定是每个颜色最多一次贡献。

在这里插入图片描述

代码

#include <bits/stdc++.h>

using namespace std;

const int N = 5e5+10;
int pos[N], c[N], a[N], nowPos = 1;
int n, q;

struct Node
{
    int first, second, id, ans;
} qs[N];


int query(int x)
{
	int res = 0;
	for(;x;x-=x&(-x)) res += c[x];
	return res;
}

void insert(int x, int d)
{
	for(;x<=n;x+=x&(-x)) c[x] += d;
}

bool cmp(Node a, Node b)
{
	return a.second < b.second;
}

bool cmp2(Node a, Node b)
{
    return a.id < b.id;
}

signed main()
{
	cin >> n >> q;
	for(int i = 1; i <= n; i ++)
	{
		cin >> a[i];
	}
	for(int i = 1; i <= q; i ++)
	{
		cin >> qs[i].first >> qs[i].second;
        qs[i].id = i;
	}
    
	sort(qs+1, qs+1+q, cmp);
	for(int i = 1; i <= q; i ++)
	{
		for(int j = nowPos; j <= qs[i].second; j ++)
		{

			if(pos[a[j]] == 0)
			{
				insert(j, 1);
				pos[a[j]] = j;
			}
			else
			{
				insert(pos[a[j]], -1);
				insert(j, 1);
				pos[a[j]] = j; 
			}
		}
		nowPos = qs[i].second + 1;
        
        // 这样直接输出是不对的啊
        // 排序之后就不是原来的询问顺序了
        // cout << query(qs[i].second) - query(qs[i].first-1) << endl;

        qs[i].ans = query(qs[i].second) - query(qs[i].first-1);
	}
    sort(qs+1, qs+1+q, cmp2);
    for(int i = 1; i <= q; i ++)
    {
        cout << qs[i].ans << endl;
    }
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

善良的大铁牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值