AtCoder Regular Contest 098~102

AtCoder Regular Contest 098

F. Donation

题解

AtCoder Regular Contest 099

F. Eating Symbols Hard

挺牛逼的题。

判断同构的首选策略是哈希,但是需要构造一个同构下相同的哈希函数。

先考虑序列哈希,那么每种操作可以看做 +1,1,×b,÷b

考虑求出前缀操作的变化 fi,指针位移 ri,那么对于一段区间 (i,j] 变化是 fjfibrjri,要求这个值等于 fn。直接移项之后用 map 统计即可。

但是直接处理会有问题:指针的位置不同不认为不同。考虑这样影响的只是一堆指针移动操作,所以不妨在位移的时候不直接计入 f 即可。

复杂度 O(nlogn)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#define N 250010
using namespace std;
int ksm(int a,int b,int mod)
{
    int r=1;
    for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) r=1ll*r*a%mod;
    return r;
}
struct node{
    int x,y;
    node(int X,int Y):x(X),y(Y){}
    node(int X=0):x(X),y(X){}
    bool operator <(const node a)const{return x==a.x?y<a.y:x<a.x;}
};
const int mod1=1000000007,mod2=1019260817;
node operator +(const node a,const node b){return node((a.x+b.x)%mod1,(a.y+b.y)%mod2);}
node operator -(const node a,const node b){return node((a.x-b.x+mod1)%mod1,(a.y-b.y+mod2)%mod2);}
node operator *(const node a,const node b){return node(1ll*a.x*b.x%mod1,1ll*a.y*b.y%mod2);}
node operator /(const node a,const node b){return node(1ll*a.x*ksm(b.x,mod1-2,mod1)%mod1,1ll*a.y*ksm(b.y,mod2-2,mod2)%mod2);}
const node B=2333,Bi=1/B;
char s[N];
node f[N],g[N];
map<node,int>st;
int main()
{
    int n;
    scanf("%d%s",&n,s+1);
    g[0]=1;
    for(int i=1;i<=n;i++)
    {
        if(s[i]=='-') g[i]=g[i-1],f[i]=f[i-1]-g[i];
        if(s[i]=='+') g[i]=g[i-1],f[i]=f[i-1]+g[i];
        if(s[i]=='<') g[i]=g[i-1]*Bi,f[i]=f[i-1];
        if(s[i]=='>') g[i]=g[i-1]*B,f[i]=f[i-1];
    }
    long long ans=0;
    for(int i=n;i>=0;i--) ans+=st[f[i]+f[n]*g[i]],st[f[i]]++;
    printf("%lld\n",ans);
    return 0;
}

AtCoder Regular Contest 100

F. Colorful Sequences

首先正难则反,显然 A 在所有串中的出现次数是 Knm(nm+1)

要求的是没有长度为 K 的每个数字只出现一次的区间。求这样的区间中 A 出现次数。

如果 A 本来就是 colorful 的,显然就是 0

如果 A 两两不同,可以发现 A 的实际数值对答案没有影响,只需要求出没有有长度为 m 的出现次数然后除以总个数即可。

如果 A 存在相同,那么取第一个相同的位置与最后一个相同的位置即可。剩下就是一个卷积了。

复杂度 O(NK)

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=25010,M=410,mod=1000000007;
int fac[N],inv[N];
int ksm(int a,int b=mod-2)
{
    int r=1;
    for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) r=1ll*r*a%mod;
    return r;
}
int C(int a,int b){return a<b?0:1ll*fac[a]*inv[b]%mod*inv[a-b]%mod;}
void init(int n=N-10)
{
    fac[0]=1;
    for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%mod;
    inv[n]=ksm(fac[n]);
    for(int i=n-1;i>=0;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
}
int n,m,k,a[N];
int f[N][M],g[N][M],s[M];
void pre_work()
{
    s[0]=f[0][0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=min(i,k);j++) f[i][j]=(f[i][j]+s[j]+1ll*f[i-1][j-1]*(k-j+1)%mod)%mod;
        for(int j=k-1;~j;j--) s[j]=(s[j+1]+f[i][j])%mod;
    }
}
int tot[M];
bool colorful()
{
    int res=0;
    for(int i=0;i<=k;i++) tot[i]=0;
    for(int i=1;i<=m;i++)
    {
        if(i>k) res-=!(--tot[a[i-k]]);
        res+=!(tot[a[i]]++);
        if(res==k) return true;
    }
    return false;
}
bool same()
{
    for(int i=0;i<=k;i++) tot[i]=0;
    for(int i=1;i<=m;i++) if(tot[a[i]]++) return true;
    return false;
}
int main()
{
    scanf("%d%d%d",&n,&k,&m);
    init();pre_work();
    for(int i=1;i<=m;i++) scanf("%d",&a[i]);
    int ans=1ll*ksm(k,n-m)*(n-m+1)%mod;
    if(colorful()){printf("%d\n",ans);return 0;}
    if(same())
    {
        int l=0,r=0;
        for(int i=0;i<=k;i++) tot[i]=0;
        for(int i=1;i<=m;i++) if(tot[a[i]]++){l=i-1;break;}
        for(int i=0;i<=k;i++) tot[i]=0;
        for(int i=m;i;i--) if(tot[a[i]]++){r=m-i;break;}
        for(int i=l;i<=n;i++)
        {
            int d=i-l+m,r1=0,r2=0;if(d>n) break;
            for(int j=l;j<k;j++) r1=(r1+1ll*f[i][j]*fac[k-l]%mod*inv[k])%mod;
            for(int j=r;j<k;j++) r2=(r2+1ll*f[n-d+r][j]*fac[k-r]%mod*inv[k])%mod;
            ans=(ans-1ll*r1*r2%mod+mod)%mod;
        }
        printf("%d\n",ans);
        return 0;
    }
    memset(s,0,sizeof(s));
    s[0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=min(i,k);j++)
        {
            g[i][j]=(g[i][j]+s[j]+1ll*g[i-1][j-1]*(k-j+1)%mod)%mod;
            if(j>=m) g[i][j]=(g[i][j]+f[i][j])%mod;
        }
        for(int j=k-1;~j;j--) s[j]=(s[j+1]+g[i][j])%mod;
    }
    int res=0;
    for(int i=1;i<k;i++) res=(res+g[n][i])%mod;
    res=1ll*res*fac[k-m]%mod*inv[k]%mod;
    printf("%d\n",(ans-res+mod)%mod);
    return 0;
}

AtCoder Regular Contest 101

E. Ribbons on Tree

题解

F. Robots and Exits

题解

AtCoder Regular Contest 102

F. Revenge of BBuBBBlesort!

首先可以发现如果 i 位置发生了一次交换,那么可以证明 i 位置就不能被移动了。

所以交换中心一定有 pi=i

bi=[pi=i],那么 b 的连续值之间切开,可以将序列分成若干段。对于每段,首先值域必须完全符合该段左右端点,其次必须有最长下降子序列不超过 2

直接贪心求两遍上升子序列即可。

复杂度 O(n)

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 300010
using namespace std;
int a[N],b[N];
inline void No(){puts("No");exit(0);}
inline void Yes(){puts("Yes");exit(0);}
bool vis[N];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i]==i;
    for(int i=1;i<=n;i++) if(!b[i-1] && !b[i] && !b[i+1]) No();
    b[0]=1;
    for(int l=0,r=0;l<=n;l=r)
    {
        while(b[l]) l++,r++;
        if(l>n) break;
        for(r++;r<=n && b[r-1]!=b[r];r++);
        int mn=n,mx=0;
        for(int i=l;i<r;i++) mn=min(mn,a[i]),mx=max(mx,a[i]);
        // printf("%d %d %d %d\n",l,r-1,mn,mx);
        if(mn!=l || mx!=r-1) No();
        for(int i=l,pr=0;i<r;i+=2) if(a[i]>pr) vis[i]=true,pr=a[i];
        for(int i=l,pr=0;i<r;i+=2) if(!vis[i] && a[i]>pr) vis[i]=true,pr=a[i];
        for(int i=l;i<r;i++) if(!b[i] && !vis[i]) No();
    }
    Yes();
    return 0;
}
posted @   Flying2018  阅读(10)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示