欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Eggfruit Cake(尺取)

程序员文章站 2022-06-04 16:11:38
...

问题 E: Eggfruit Cake
时间限制: 1 Sec 内存限制: 128 MB

题目描述
Today is Jaime’s birthday and, to celebrate, his friends ordered a cake decorated with eggfruits and persimmons. When the cake arrived, to their surprise, they noticed that the bakery didn’t use equal amounts of eggfruits and persimmons, but just randomly distributed the fruits over the cake’s border instead.
Jaime eats persimmons every day, so he was eager to try some eggfruit on his birthday.
However, as he doesn’t want to eat too much, his cake slice should be decorated with at most S fruits. Since Jaime doesn’t like when a fruit is cut into parts, each fruit should either be entirely in his slice or be left in the rest of the cake. The problem is, with the fruits distributed in such a chaotic order, his friends are having trouble cutting a suitable slice for him.
Jaime is about to complain that his friends are taking too long to cut his slice, but in order to do so, he needs to know how many different slices with at least one eggfruit and containing at most S fruits there are. A slice is defined just based on the set of fruits it contains. As Jaime is quite focused on details, he is able to distinguish any two fruits, even if both fruits are of the same type. Hence, two slices are considered different when they do not contain exactly the same set of fruits. The following picture shows a possible cake, as well as the six different slices with at most S = 2 fruits that can be cut from it.
Eggfruit Cake(尺取)

输入
The first line contains a circular string B (3 ≤ |B| ≤ 105) describing the border of the cake.Each character of B is either the uppercase letter “E” or the uppercase letter “P”, indicating
respectively that there’s an eggfruit or a persimmon at the border of the cake. The second line contains an integer S (1 ≤ S < |B|) representing the maximum number of fruits that a slice can contain.
输出
Output a single line with an integer indicating the number of different slices with at most S fruits and at least one eggfruit.
样例输入 Copy
【样例1】
PEPEP
2
【样例2】
EPE
1
【样例3】
PPPP
1
【样例4】
EPEP
2
样例输出 Copy
【样例1】
6
【样例2】
2
【样例3】
0
【样例4】
6
题意:
就是给出你一个循环序列(就是首尾系相连)然后给出你一个长度尾 M M M的卡尺 卡出来长度小于等于 M M M的序列,如果卡出来的序列有“E”就算,没有即不算。问一共有几种算的。
思路:尺取 尺取 尺取*
就是利用尺取的思想,一直分。
具体:就是分成这两段,把前一段放在后面看,(因为我们看 i i i的时候看以 i i i结尾的满足条件的)然后,我们看第一个点 m m m
大前提:以m结尾,就是m一直不变

  1. 如果 m m m点是E那么不用说他从长度为1到长度尾m的都满足条件所以一共m种
  2. 如果 m m m点是P那么那就得找他前一个为E的位置,因为这样他取的区间中才有E,才能满足条件,所以符合条件的一共有(卡尺最长度m-(当前位置m-前一个E的位置));这里就用到了尺取。

上述的2.因为m的问题容易误解 因为是推广所以这样理解:
假设当前点是x(x>=m)是 P P P那么就得找他前面一个 E E E的位置,因为这样他取的区间(从x点往前取,都往一个方向取就不会重复也不会漏)中才有 E E E才能满足条件,所以符合条件的一共有(卡尺长度m-(当前位置x-前一个E的位置));


接而推出 m − l e n m-len mlen都是这样的,到了(len—len+m-1)这就会出来(m-(当前位置-前一个E的位置))。
注意**(当前位置-前一个E的位置)**如果隔的P太多会造成差为负数,所以为了避免这种就需要max(0,这个);就像这样的

EEPPPPPPPPPPPPPPPPPE
3

正确是12
不正确-93
加abs就是117
所以就是这个地方的错误


    for(int i=m; i<len+m; i++) {
        if(a[i]!=0) {
            sum+=max(0ll,m-(i-a[i]));///会出来负数,所以要用max(0,)
        }
    }

还有一点就是需要注意就是如果前 m + X m+X m+X都是P的话
所以就需要加上这个判断了

	if(a[i]!=0) 

具体看看全部代码吧。

Eggfruit Cake(尺取)
代码:

#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
#include <immintrin.h>
#pragma GCC optimize(2)
#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
typedef pair<ll,ll> pii;
#define mem(a,x) memset(a,x,sizeof(a))
#define debug(x) cout << #x << ": " << x << endl;
#define rep(i,n) for(int i=0;i<(n);++i)
#define repi(i,a,b) for(int i=int(a);i<=(b);++i)
#define repr(i,b,a) for(int i=int(b);i>=(a);--i)
const int maxn=2e6+1010;
#define inf 0x3f3f3f3f
#define sf scanf
#define pf printf
const int mod=998244353;
const int MOD=10007;

inline int read() {
    int x=0;
    bool t=false;
    char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}

/*
vector<ll> m1;
vector<ll> m2;
priority_queue<ll , vector<ll> , greater<ll> > mn;//上  小根堆 		小到大
priority_queue<ll , vector<ll> , less<ll> > mx;//下   	大根堆  	大到小
map<ll,ll>mp;*/
ll n,m;
char str[maxn];
ll a[maxn];
ll sum;
#define read read()
int main() {
    cin>>str+1;
    ll len=strlen(str+1);
    ll l=0;
    cin>>m;
    for(int i=1; i<=len; i++) {
        if(str[i]=='E') {
            l=i;
            a[i]=i;
        } else {
            a[i]=l;
        }
    }
    for(int i=len+1;i<len+m;i++){
        if(str[i-len]=='E') {
            l=i;
            a[i]=i;
        } else {
            a[i]=l;
        }
    }

    for(int i=m; i<len+m; i++) {
        if(a[i]!=0) {
            sum+=max(0ll,m-(i-a[i]));///会出来负数,所以要用max(0,)
        }
    }
    /**
    这个地方会废掉3个后台数据。
    出现负数原因:因为a[i]记录的是前一个所以i-a[i]这样的话最后一个跟刚开始的差得太多就会导致(i-a[i])就会出现负数

    */
    cout<<sum<<endl;
    return 0;
}

相关标签: 尺取