这次应该叫高二上一调

A.匹配

我神奇的从火星人profix里获得了搞一个hash后缀数组的灵感,这样就可以直接对应了。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2e5 + 3;
const int N = 1e5 + 3;

int T, la, lb;
ull p[maxn], ha[maxn], hb[maxn];
char s[maxn], d[2];

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()
{
    T = read();
    p[0] = 1;
    for(int i=1; i<=N; i++)
    {
        p[i] = p[i-1] * 233;
    }
    while(T--)
    {
        la = read(); lb = read();
        scanf("%s", s+1);
        scanf("%s", d);
        memset(ha, 0, sizeof(ha));
        memset(hb, 0, sizeof(hb));
        for(int i=1; i<=la; i++)
        {
            ha[i] = ha[i-1] * 233 + (s[i]-'a'+1);
        }
        hb[lb+1] = d[0] - 'a' + 1;
        for(int i=lb; i>=1; i--)
        {
            hb[i] = hb[i+1] + (s[i]-'a'+1) * p[lb-i+1];
        }
        int n = min(la, lb+1), ans = 0;
        for(int i=n; i>=1; i--)
        {
            if(s[i] == d[0])
            {
                if(i == 1)
                {
                    ans = 1; break;
                }
                if(s[lb+2-i] == s[1])
                {
                    if(ha[i] == hb[lb+2-i])
                    {
                        ans = max(ans, i);
                        break;
                    }
                }
            }
        }
        printf("%d\n", ans);
    }

    return 0;
}
View Code

B.回家

本来打算先找完割点,再从n点dfs一下到1停止找到在路径上的点,最后两个都满足就是答案。

少了一种情况:5 5

1 3

1 2

3 4

3 5

2 5

不是所有既在路径上又是割点的点就是从1到n路径上的割点。能把一个点判定为另一个点一定要在路径上。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 2e6 + 3;
const int N = 4e6 + 3;

int T, n, m, dfn[maxn], cnt, num;
bool iscut[maxn], acc[maxn];

struct node
{
    int next, to;
}a[N];
int head[maxn], len;

void In(int x, int y)
{
    a[++len].to = y; a[len].next = head[x];
    head[x] = len;
}

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 dfs(int u, int f)
{
    int lowu = dfn[u] = ++dfs_c;
    for(int i=head[u]; i; i=a[i].next)
    {
        int v = a[i].to;
        if(v == f) continue;
        if(!dfn[v])
        {
            int lowv = dfs(v, u);
            lowu = min(lowu, lowv);
            if(lowv >= dfn[u] && acc[v])
            {
                iscut[u] = true;
            }
        }
        else 
        {
            lowu = min(dfn[v], lowu);
        }
        acc[u] |= acc[v];
    }
    return lowu;
}*/

int low[maxn];
void tarjan(int x, int fa)
{
    //v[x] = true;
    dfn[x] = low[x] = ++num;

    bool first = true;
    int son = 0;
    for(int i=head[x]; i; i=a[i].next)
    {
        int to = a[i].to;
        if(first && to == fa)
        {
            first = false;
            continue;
        }
        if(!dfn[to])
        {
            son++;
            tarjan(to, x);
            low[x] = min(low[x], low[to]);

            if(dfn[x] <= low[to] && acc[to])
            {
                iscut[x] = true;
            }
        }
        else 
        {
            low[x] = min(low[x], dfn[to]);
        }
        acc[x] |= acc[to];
    }
}

void solve()
{
    acc[n] = true;
    tarjan(1, 0);
    for(int i=2; i<n; i++)
    {
        if(iscut[i]) cnt++;
    }
    printf("%d\n", cnt);
    for(int i=2; i<n; i++)
    {
        if(iscut[i])
        {
            printf("%d ", i);
        }
    }
    printf("\n");
}

void clear()
{
    num = len = cnt = 0;
    memset(head, 0, sizeof(head));
    memset(dfn, 0, sizeof(dfn));
    memset(acc, false, sizeof(acc));
    memset(iscut, 0, sizeof(iscut));
}

int main()
{
    T = read();
    while(T--)
    {
        clear();
        n = read(); m = read();
        for(int i=1; i<=m; i++)
        {
            int x = read(), y = read();
            In(x, y); In(y, x);
        }
        solve();
    }

    return 0;
}
View Code

C.寿司

1.可以枚举一个中心点让左边的点和右边的点向它靠拢,交换次数就是坐标的差再减去中间相同颜色的点数。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 2e6 + 3;
const int N = 4e6 + 3;
const int INF = 0x3f3f3f3f;

int T, len;
char s[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()
{
    T = read();
    while(T--)
    {
        scanf("%s", s);
        len = strlen(s);
        int ans = INF;
        for(int i=0; i<len; i++)
        {
            int sum = 0;
            int nowl = i, cntl = 0, nowr = i, cntr = 0;
            for(int j=1; j<=(len+1)/2-1; j++)
            {
                nowl--;
                int now = nowl;
                if(now < 0)
                {
                    now = (now + len) % len;
                }
                if(s[now] == s[i])
                {
                    cntl++;
                    sum += i-nowl-cntl;
                }
            }
            for(int j=1; j<=(len+1)/2-1; j++)
            {
                nowr++;
                int now = nowr;
                if(now >= len)
                {
                    now %= len;
                }
                if(s[now] == s[i])
                {
                    cntr++;
                    sum += nowr-i-cntr;
                }
            }
            if(!(len&1))
            {
                if(s[i] == s[(i+len/2)%len])
                {
                    if(cntl > cntr)
                    {
                        cntl++;
                        sum += len/2-cntl;
                    }
                    else 
                    {
                        cntr++;
                        sum += len/2-cntr;
                    }
                }
            }
            if(sum < ans)
            {
                ans = sum;
            }
        }
        printf("%d\n", ans);
    }

    return 0;
}
eps 40

2.比较神奇的预处理,但我怀疑这个诡异的下标是题解写复杂了。可以提前把每个格子当中心点需要移动的次数记录下来,找到一个可以推出它旁边的,然后就可以直接用了。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 2e6 + 3;
const int N = 4e6 + 3;
const ll INF = 1e17;

int T, len, a[maxn];
ll f[2][2][maxn], cnt[2][2][maxn];
char s[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()
{
    T = read();
    while(T--)
    {
        memset(f, 0, sizeof(f));
        memset(cnt, 0, sizeof(cnt));
        scanf("%s", s);
        len = strlen(s);
        for(int i=0; i<len; i++)
        {
            if(s[i] == 'R') a[i] = 0;
            else a[i] = 1;
        }
        ll ans = INF;
        for(int i=0; i<=(len+1)/2-2; i++)
        {
            cnt[0][a[i]][0]++;
            f[0][a[i]][0] += i-cnt[0][a[i]][0]+1;
        }
        for(int i=1; i<=len; i++)
        {
            cnt[0][0][i] = cnt[0][0][i-1];
            cnt[0][1][i] = cnt[0][1][i-1];
            cnt[0][a[i-1]][i]--;
            f[0][0][i] = f[0][0][i-1];
            f[0][1][i] = f[0][1][i-1];
            f[0][1-a[i-1]][i] -= cnt[0][1-a[i-1]][i];
            cnt[0][a[(i+(len+1)/2-2)%len]][i]++;
            f[0][a[(i+(len+1)/2-2)%len]][i] += (len+1)/2-1-cnt[0][a[(i+(len+1)/2-2)%len]][i];
        }
        for(int i=len-1; i>=len-(len-1)/2; i--)
        {
            cnt[1][a[i]][len-1]++;
            f[1][a[i]][len-1] += len-i-cnt[1][a[i]][len-1];
        }
        for(int i=len-2; i>=0; i--)
        {
            cnt[1][0][i] = cnt[1][0][i+1];
            cnt[1][1][i] = cnt[1][1][i+1];
            cnt[1][a[i+1]][i]--;
            f[1][0][i] = f[1][0][i+1];
            f[1][1][i] = f[1][1][i+1];
            f[1][1-a[i+1]][i] -= cnt[1][1-a[i+1]][i];
            cnt[1][a[(i-(len+1)/2+2+len)%len]][i]++;
            f[1][a[(i-(len+1)/2+2+len)%len]][i] += (len+1)/2-1-cnt[1][a[(i-(len+1)/2+2+len)%len]][i];
        }
        for(int i=0; i<len; i++)
        {
            ll sum = f[0][a[i]][(i+1)%len]+f[1][a[i]][(i-1+len)%len];
            if(!(len&1))
            {
                if(a[i] == a[(i+len/2)%len])
                {
                    if(cnt[0][a[i]][(i+1)%len] > cnt[1][a[i]][(i-1+len)%len])
                    {
                        sum += len/2-cnt[0][a[i]][(i+1)%len];
                    }
                    else 
                    {
                        sum += len/2-cnt[1][a[i]][(i-1+len)%len];
                    }
                }
            }
            if(sum < ans)
            {
                ans = sum;
            }
        }
        printf("%lld\n", ans);
    }

    return 0;
}
View Code

3.好像有更快的方法,等我去研究一下……

其实就是方法一的式子化简一下,其中有一个部分可以用等差数列求和公式,Nothing else~

改天再更新代码。。更新也是抄的。。

posted @ 2022-07-09 09:01  Catherine_leah  阅读(13)  评论(0编辑  收藏  举报
/* */