NOIP多校联考5

A.旅行日记

错误的更新:

    Max = h[1]+d[1]-1;
    Max = max(Max, h[m]-d[m]+n);
    for(int i=1; i<m; i++)
    {
        Max = max(Max, h[i]);
        if(d[i+1]-d[i] > 1)
        {
            int tmp = h[i+1]-h[i], r = d[i+1]-d[i];
            t += tmp;
            Max = max(Max, h[i+1]+r/2);
        }
    }

有卖后悔药的吗?——正确的更新1

    Max = h[1]+d[1]-1;
    Max = max(Max, h[m]-d[m]+n);
    for(int i=1; i<m; i++)
    {
        Max = max(Max, h[i]);
        if(d[i+1]-d[i] > 1)
        {
            int tmp = h[i+1]-h[i], r = d[i+1]-d[i];
            r += tmp;
            Max = max(Max, h[i]+r/2);//其实就是h[i+1]换成了h[i],
            //这是什么傻乎乎的低错啊!!!
        }
    }

正解就在草稿纸上好好的躺着……话说写成这样还有80分,本来应该爆0的……

题解上的式子比我的简单了不少,似乎更容易避免瞎打:——完整版

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e5 + 2;
const ll mod = 1e9 + 7;
const int INF = 0x7ffffff;

int n, m, d[maxn], h[maxn], Max;

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

bool check()
{
    for(int i=2; i<=m; i++)
    {
        if(h[i]-h[i-1] > d[i]-d[i-1]) return 0;
    }
    return 1;
}

int main()
{
    n = read(); m = read();
    for(int i=1; i<=m; i++)
    {
        d[i] = read(); h[i] = read();
    }
    if(!check())
    {
        printf("IMPOSSIBLE"); exit(0);
    }
    Max = h[1]+d[1]-1;
    Max = max(Max, h[m]-d[m]+n);
    for(int i=1; i<m; i++)
    {
        Max = max(Max, h[i]);
        if(d[i+1]-d[i] > 1)
        {
            int tmp = h[i+1]-h[i], r = d[i+1]-d[i];
            r += tmp;
            Max = max(Max, h[i]+r/2);//其实就是h[i+1]换成了h[i],
            //这是什么傻乎乎的低错啊!!!
        }
    }
    printf("%d", Max);
    
    return 0;
}
View Code

B.运动

两天之内MLE两次,谁都不服就服你……话说我那个二分过大样例还挺顺的,除了傻乎乎的二维数组开了一堆之外,总感觉他没什么问题……

感觉官方题解就很清楚了:
运动:
单调队列
维护两个单调队列,一个 eggache 值递增,另一个递减。

当两个队头的差大于 k 时,较左的出队,队中元素最左变为出队元素位置+1

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 3e6 + 2;
const ll mod = 1e9 + 7;
const int INF = 0x7ffffff;

int a[maxn], k, n, h1, h2, t1, t2, q1[maxn], ans, q2[maxn], pos;

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

int main()
{
    //freopen("sport2.in", "r", stdin);
    
    k = read(); n = read();
    for(int i=1; i<=n; i++)
    {
        a[i] = read();
    }
    h1 = 1, h2 = 1, t1 = 0, t2 = 0;
    pos = 1;
    for(int i=1; i<=n; i++)
    {
        while(t1 >= h1 && a[i] > a[q1[t1]]) t1--;
        q1[++t1] = i; 
        while(t2 >= h2 && a[i] < a[q2[t2]]) t2--;
        q2[++t2] = i; 
        while(t1 >= h1 && t2 >= h2 && a[q1[h1]]-a[q2[h2]] > k)
        {
            if(q1[h1] < q2[h2]) h1++, pos = q1[h1-1]+1;
            else h2++, pos = q2[h2-1]+1;
        }
        ans = max(ans, i-pos+1);
    }
    printf("%d", ans);
    
    return 0;
}
View Code

 C.回文

赛时用manacher抢了40分,但是由于机房忽然停电代码没存上,收藏不了了,好可惜哦。

一看题解就恍然大悟,不看题解就迷迷糊糊……

公式真好用,好像不止一次见过这种东西……

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 5001;
const ll mod = 1e9 + 7;
const int INF = 0x7ffffff;

char s[maxn];
ll f[maxn][maxn];
ll n, q;
bool g[maxn][maxn];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

int main()
{
    //freopen("pal2.in", "r", stdin);
    
    scanf("%s", s+1);
    n = strlen(s+1);
    for(int i=n; i>=1; i--)
    {
        g[i][i] = 1;
        for(int j=i+1; j<=n; j++)
        {
            if(s[i] == s[j])
            {
                g[i][j] = g[i+1][j-1];
                if(j == i+1) g[i][j] = 1;
            }
        }
    }
    for(int i=n; i>=1; i--)
    {
        for(int j=i; j<=n; j++)
        {
            f[i][j] = f[i+1][j]+f[i][j-1]-f[i+1][j-1]+g[i][j];
        }
    }
    q = read();
    while(q--)
    {
        int x = read(), y = read();
        printf("%lld\n", f[x][y]);
    }
    
    return 0;
}
View Code

 D.基因进化

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 5001;
const ll mod = 998244353;
const int INF = 0x7ffffff;

int T, n, m, a[maxn], b[maxn], c[maxn], d[maxn];
ll ans;

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

void work(int num)
{
    int w = 1;
    while(num)
    {
        if(num&1) reverse(d+1, d+w+1);
        num >>= 1;
        w++;
    }
}

bool nice()
{
    for(int i=1; i<=n; i++)
    {
        if(d[i] < c[i]) return 1;
        else return 0;
    }
    return 0;
}

void Cathy()
{
    for(int i=1; i<=n; i++)
    {
        c[i] = d[i];
    }
}

bool check(int num)
{
    for(int i=1; i<=m; i++)
    {
        if((1<<(b[i]-1)) & num) return 0;
    }
    return 1;
}

int main()
{
    //freopen("reverse1.in", "r", stdin);

    T = read();
    while(T--)
    {
        n = read(); m = read();
        ans = 0;

        for(int i=1; i<=n; i++)
        {
            a[i] = read(); c[i] = a[i];
        }
        for(int i=1; i<=m; i++)
        {
            b[i] = read();
        }
        int Max = (1<<n);
        for(int i=1; i<Max; i++)
        {
            if(!check(i)) continue;
            for(int j=1; j<=n; j++) d[j] = a[j];
            work(i);
            if(nice()) Cathy();
        }
        for(int i=n; i>=1; i--)
        {
            ans = (ans * 37 % mod + c[i]) % mod;
        }
        printf("%lld\n", ans);
    }
    
    return 0;
}
别看了这是0分TLE+WA

 把翻转考虑成插入:假设前面的2位操作可得的最小值是AB,我要加入C,一种是BAC,另一种是CAB(ABC->BAC->CAB),再考虑中间有不能翻的,还是AB已确定最小,CD不能翻,我要加入E,一种是ABCDE,另一种是EDCAB(ABCDE->BACDE->EDCAB)

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 5001;
const ll mod = 998244353;
const int INF = 0x7ffffff;

bool nrt[300005];
int s[300005], n, m;

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

void deal()
{
    for(int i=1; i<=n; i++)
    {
        nrt[i] = 0;
    }
    n = read(); m = read();
    for(int i=1; i<=n; i++)
    {
        s[i] = read();
    }
    for(int i=1; i<=m; i++)
    {
        int hac = read(); nrt[hac] = 1;
    }
    //以下步骤完全模拟每一步的插入和翻转
    int tiao = 0;
    for(int i=2; i<=n; i++)//枚举翻哪位
    {
        if(nrt[i])
        {
            tiao++;//插入的区间的长度-1,i到j之间的数
            continue;
        }
        int fan = i, zhen = 1;//zhen是开头,fan是现在的位置,两种插入后可能作为起点的情况
        int op = 1;
        bool zhenxiao = 1;//插入的数放后面,情况2
        int nct = 0;
        while(nct <= i)
        {
            if(s[fan] > s[zhen])
            {
                zhenxiao = 1; break;
            }
            if(s[zhen] > s[fan])
            {
                zhenxiao = 0; break;
            }
            //第一位相同,倒着继续往下比
            ++nct;
            ++zhen;
            if(op) --fan;
            else ++fan;
            //如果插入在前面和插入在后面一样,还要继续比较后面,相当于跳到了开头
            if(fan == i-tiao-1) op = 0, fan = 1;
        }
        if(!zhenxiao)//插到前面==先翻前面再翻整体
        {
            reverse(s+1, s+1+i-tiao-1);
            reverse(s+1, s+1+i);
        }
        tiao = 0;
    }
    ll hsh = 0;
    for(int i=n; i>=1; i--)
    {
        hsh = (hsh*37+1ll*s[i])%mod;
    }
    printf("%lld\n", hsh);
    return;
}

int main()
{
    //freopen("reverse1.in", "r", stdin);

    int op = read();
    while(op--)
    {
        deal();
    }
    
    return 0;
}
TLE60 感谢caorong

至于正解……谁来救救我吧……

posted @ 2022-07-25 20:15  Catherine_leah  阅读(35)  评论(0编辑  收藏  举报
/* */