codeforce round 7

E

题意真的是看瞎眼,题意:要输出每个位置i—th使得求出q1~q(i-1)有效的情况下答案是多少;
每次在i-th操作,我们要执行将p1,p2.p3依次放进空集里面,那么轮到q位置,例如q=5,那就是第五个p数字
他就要爆炸,使得这个集合最大的元素炸飞,然后执行完q1~q(i-1)后,该集合的最大元素是谁
那么第i—th个输出的就是这个元素;
那么我们应该怎么做呢,我们首先先发现这个最后输出的序列肯定是个单调不递增,那么!!
那么就会发现我们是不是可以考虑从头到尾直接从大到小枚举,只要满足条件,那就输出!!
那现在看一下是什么条件,我们假定该位置的正确答案本来应该是x,那么现在我们是从大到小枚举,枚举到了一个大于x的,
但是实际上答案是x的,枚举到大于x的要被一个判断条件将这个大于的给pass掉,怎么pass掉呢?
想当然这个大于x的之所以不是答案是因为他被炸掉了,被炸掉了说明在前i个q操作中,必须有一次操作操作到这个大于x的位置的右边
使得他会被炸掉,至少有一个炸弹,有多少个无所谓;
接下来就是讨论怎么做,我们知道从第1个到第i个,是有叠加性的,前面的处理后可以到后面接着用
我们知道一个炸弹位置,例如在k位置,他只会影响1到k这里的最大数,而我们又是从大到小
枚举,那么我们只要每次炸弹操作都将一个区间给给覆盖-1,不过毕竟第i个输出不会用到第i个q,所以我们先更新当前第
i个入队数字的区间全部++,判断1到n区间是否有1,没1说明这个数字的位置覆盖位置无法超过q炸弹的影响位置
难逃一吸,那就只能--,寻找这个新的x位置有1说明当前数字x可以覆盖掉炸弹位置也就是前i个操作的炸弹这次没法炸到这个个位置,那就输出

#include<iostream>
#include<string>
#include<string.h>
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
const int maxn=3e5+10;
int tree[maxn<<2],lazy[maxn<<2],a[maxn],p[maxn],id[maxn];
void pushdown(int rt)
{
    tree[lson]+=lazy[rt];
    tree[rson]+=lazy[rt];
    lazy[lson]+=lazy[rt];
    lazy[rson]+=lazy[rt];
    lazy[rt]=0;
}
void pushup(int rt)
{
    tree[rt]=max(tree[lson],tree[rson]);
}
void update(int L,int R,int x,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        tree[rt]+=x;
        lazy[rt]+=x;
        return;
    }
    pushdown(rt);
    int mid=(l+r)/2;
    if(L<=mid)
        update(L, R, x,l, mid, lson);
    if(mid<R)
        update(L, R, x,mid+1, r, rson);
    pushup(rt);
}
int q(int L,int R,int l,int r,int rt)
{
    pushdown(rt);
    if(L<=l&&r<=R)
    {
        return tree[rt];
    }
    int mid=(l+r)/2;
    int ans=0;
    if(L<=mid)
        ans=max(ans,q(L, R, l, mid, lson));
    if(mid<R)
        ans=max(ans,q(L, R, mid+1, r, rson));
    return ans;
}
int n;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        id[a[i]]=i;
    }
    for(int i=1;i<=n;i++)
        cin>>p[i];
    int now=n;
    update(1,id[n], 1, 1, n ,1);
    for(int i=1;i<=n;i++)
    {
        cout<<now<<" ";
        if(i==n)
            break;
        update(1, p[i], -1, 1, n, 1);
        while(q(1, n, 1, n, 1)<=0)
        {
            now--;
            update(1,id[now], 1, 1, n, 1);
        }
    } 
}

  

D2. Prefix-Suffix Palindrome (Hard version)

题意:
给出一个字符串ss。
现在要找到一个最长的串tt,满足:

  • tt为一个回文串;
  • t=pres+sufst=pres+sufs,即是ss串不重叠的前缀和后缀的拼接。

思路:
可以注意到若ss串首尾字符相同,那么我们可以直接去除不影响答案。
简要证明:

    • 如果最后会去除一段前缀和一段后缀,那么我们一开始去掉不会影响答案,这种情况不用考虑。
    • 马拉车算法稍微改一下就是我们要这一段必须要么开头开始的回文要么是结尾开始的回文因为是链接在一起的
    • #include <bits/stdc++.h>
      #define pb(x) push_back(x)
      #define mp(x, y) make_pair(x, y)
      #define fast ios::sync_with_stdio(false)
      #define mset(a, n) memset(a, n, sizeof(a))
      #define forn(i, n) for (int i = 0; i < (n); ++i)
      #define forab(i, a, b) for (int i = (a); i <= (b); ++i)
      #define forba(i, b, a) for (int i = (b); i >= (a); --i)
      #define db double
      #define ll long long
      #define endl '\n'
      #define fi first
      #define se second
       
      using namespace std;
       
      typedef pair<int, int> P;
       
      inline int lowbit(int x) { return x & (-x); }
       
      const ll MOD = 1e9 + 7;
      const ll mod = 998244353;
       
      string Manacher(string &s) {
          string t = "$#";
          for (int i = 0; i < s.length(); ++i) {
              t += s[i];
              t += '#';
          }
       
          int ml = 0, p = 0, R = 0, M = 0;
       
          int len = t.length();
          vector<int> P(len, 0);
          for (int i = 0; i < len; ++i) {
              P[i] = R > i ? min(P[2 * M - i], R - i) : 1;
              while (t[i + P[i]] == t[i - P[i]]) ++P[i];
              if (i + P[i] > R) {
                  R = i + P[i];
                  M = i;
              }
              if (ml < P[i] && (i - P[i]) / 2 == 0) {
                  ml = P[i];
                  p = i;
              }
          }
       
          return s.substr((p - ml) / 2, ml - 1);
      }
       
      int main(){
          fast;
          int t;
          cin >> t;
          while (t--) {
              string s;
              cin >> s;
              int l = 0, r = s.size() - 1;
              while (s[l] == s[r] && l < r)
                  ++l, --r;
              string pre = s.substr(0, l), suf = s.substr(r + 1);
              //cout << pre << " " << suf << "\n";
              string ss = s.substr(l, r - l + 1);
              string ex = Manacher(ss);
              reverse(ss.begin(), ss.end());
              string exx = Manacher(ss);
              //cout << ss << " " << ex << " " << exx << "\n";
              if (ex.length() > exx.length())
                  cout << pre + ex + suf << "\n";
              else
                  cout << pre + exx + suf << "\n";
          }
       
          return 0;
      }
      

        

      C. Permutation Partitions

      题意:感觉题目稍微有点绕,给定一个 1n1−n 上的全排列,将这个全排列分成不相交的 kk 段,定义该划分的 valuevalue 为各段最大值的和,求该全排列所有可能划分中 valuevalue 的最大值和达到最大值的划分情况个数。

      思路:读懂题目之后思路其实就出来了,1n1−n 的全排列分成 kk 段,显然最大的 valuevalue 为前 kk 大的数之和,至于满足情况的个数,从小到大记录前 kk 个数出现的位置,每次将答案乘以相邻两数位置之差就是答案,这题两发才过,第一发我模数写错了真是***了。

    • #include <bits/stdc++.h>
      #define pb(x) push_back(x)
      #define mp(x, y) make_pair(x, y)
      #define fast ios::sync_with_stdio(false)
      #define mset(a, n) memset(a, n, sizeof(a))
      #define forn(i, n) for (int i = 0; i < (n); ++i)
      #define forab(i, a, b) for (int i = (a); i <= (b); ++i)
      #define forba(i, b, a) for (int i = (b); i >= (a); --i)
      #define db double
      #define ll long long
      #define endl '\n'
      #define fi first
      #define se second
       
      using namespace std;
       
      typedef pair<int, int> P;
       
      inline int lowbit(int x) { return x & (-x); }
       
      const ll MOD = 1e9 + 7;
      const ll mod = 998244353;
       
      vector<ll> v;
       
      int main(){
          fast;
          ll n, k;
          cin >> n >> k;
          ll ans = 0, cnt = 1;
          forab(i, 1, n){
              int x;
              cin >> x;
              if (x > (n - k)){
                  v.push_back(i);
                  ans += x;
              }
          }
          for (int i = 0; i < v.size() - 1; ++i) {
              cnt = cnt * (v[i + 1] - v[i]) % mod;
          }
          cout << ans << " " << cnt << "\n";
          return 0;
      }
      

        

posted on 2020-03-23 16:09  师姐的迷弟  阅读(122)  评论(0编辑  收藏  举报

导航