Atcoder Regular 098 区间Pre=Xor Q询问区间连续K去最小值最小极差

C

用scanf("%s")就会WA..不知道为什么

/*Huyyt*/
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int dir[8][2] = {{0, 1}, {1, 0}, {0, -1}, { -1, 0}, {1, 1}, {1, -1}, { -1, -1}, { -1, 1}};
const int mod = 1e9 + 7;
const int gakki = 5 + 2 + 1 + 19880611 + 1e9;
const int N = 3e5 + 5;
int preE[N];
int preW[N];
string f;
int main()
{
        ios_base::sync_with_stdio(0);
        cin.tie(0);
        int n;
        cin >> n;
        cin >> f;
        preE[0] = preW[0] = 0;
        for (int i = 1; i <= n; i++)
        {
                if (f[i - 1] == 'W')
                {
                        preW[i] = preW[i - 1] + 1;
                        preE[i] = preE[i - 1];
                }
                else
                {
                        preE[i] = preE[i - 1] + 1;
                        preW[i] = preW[i - 1];
                }
        }
        ll anser = INT_MAX;
        ll now;
        for (int i = 1; i <= n; i++)
        {
                now = preW[i - 1] - preW[0];
                now += preE[n] - preE[i];
                anser = min(anser, now);
        }
        cout << anser << endl;
        return 0;
}
View Code

D

题意:

给你N个非负数(1e5) 要求你求出有多少个区间内 区间和等于区间亦或和 给的数小于220

解:

因为XOR操作中 0^0=0 1^1=0 0^1=1 如果两个数相加有进位操作的话 肯定会损失值

所以我们把0特殊化 直接暴力 如果有位数重复的就不成立 所以每次查询的区间长度不会超过20

复杂度为1e6左右

/*Huyyt*/
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int dir[8][2] = {{0, 1}, {1, 0}, {0, -1}, { -1, 0}, {1, 1}, {1, -1}, { -1, -1}, { -1, 1}};
const int mod = 1e9 + 7;
const int gakki = 5 + 2 + 1 + 19880611 + 1e9;
const int N = 2e5 + 5;
ll num[N];
int last = 0;
int Left[N];
ll yihuo;
ll pre;
int main()
{
        ios_base::sync_with_stdio(0);
        cin.tie(0);
        int n;
        cin >> n;
        ll anser = 0;
        for (int i = 1; i <= n; i++)
        {
                cin >> num[i];
                Left[i] = last;
                if (num[i])
                {
                        last = i;
                }
        }
        ll now;
        ll i, j;
        for (i = 1; i <= n; i++)
        {
                yihuo = pre = num[i];
                for (j = Left[i]; j >= 1;j = Left[j])
                {
                        yihuo = yihuo ^ num[j];
                        pre += num[j];
                        if (yihuo != pre)
                        {
                                break;
                        }
                }
                anser+=i-j;
        }
        cout << anser << endl;
        return 0;
}
View Code

改进版:我们发现如果L-R区间是满足的 那么 L - R 内任意一个子区间也是满足的 即 L+1 - R 也行

所以每次取完极大满足条件的区间后 当R右移一格时 满足条件的L一定不会在前一个的左边

#include<bits/stdc++.h>
using namespace std;
int n;
long long s[555555];
long long a[555555];
long long ans;
int main(){;
    scanf("%d",&n);
    for (int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        s[i]=s[i-1]+x;
        a[i]=a[i-1]^x;
    }
    int l=1;
    for (int r=1;r<=n;r++){
        for (;(s[r]-s[l-1])!=(a[r]^a[l-1]);l++);
        ans+=r-l+1;
    }
    printf("%lld\n",ans);
} 
View Code

E

题意:

给你一个N个数(2000)的数列 每次操作可以让长度为K的连续序列内的最小值去除 你必须要去除Q次

假设这Q次中去除的最大的为X最小的为Y 问你X-Y最小可以是多少

解:

从1到N 枚举Y=A[i]

然后再找出全部原数列中可以删的不小于A[i]的数

如果找出的数的数目小于Q则不满足条件 跳过 反之则排序去第Q个减去A[i]即为一种的答案

总复杂度为N2LOGN

#include<bits/stdc++.h>
using namespace std;
int a[2005], b[2005], c[2005];
int n, k, q, ans;
int main()
{
        scanf("%d%d%d", &n, &k, &q);
        for (int i = 1; i <= n; i++)
        {
                scanf("%d", &a[i]);
        }
        ans = 1e9 + 1;
        for (int i = 1; i <= n; i++) //枚举每个作为Y的a[i]
        {
                int l = 0;
                int cnt = 0;
                for (int j = 1; j <= n + 1; j++)
                        if (a[i] > a[j])  
                        {
                                if (!l) //如果前面没有比a[i]大的 先跳过
                                {
                                        continue;
                                }
                                int r = j - 1; //这样L到R区间内所有数都是不小于a[i]的
                                for (int p = l; p <= r; p++)
                                {
                                        b[p] = a[p];
                                }
                                sort(b + l, b + r + 1);
                                for (int p = l; p + k - 1 <= r; p++)  //L到R区间内得有不小于K数目的数
                                {
                                        c[++cnt] = b[p]; //把能删的最小的都删掉
                                }
                                l = 0;
                        }
                        else if (!l) //枚举到不小于a[i]的
                        {
                                l = j;
                        }
                if (cnt < q)
                {
                        continue;
                }
                sort(c + 1, c + cnt + 1);
                //printf("%d\n",c[q]);
                ans = min(ans, c[q] - a[i]);
        }
        printf("%d\n", ans);
}
View Code

 

转载于:https://www.cnblogs.com/Aragaki/p/9112288.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值