AtCoder Regular Contest 098~102
AtCoder Regular Contest 098
F. Donation
题解
AtCoder Regular Contest 099
F. Eating Symbols Hard
挺牛逼的题。
判断同构的首选策略是哈希,但是需要构造一个同构下相同的哈希函数。
先考虑序列哈希,那么每种操作可以看做 。
考虑求出前缀操作的变化 ,指针位移 ,那么对于一段区间 变化是 ,要求这个值等于 。直接移项之后用 map 统计即可。
但是直接处理会有问题:指针的位置不同不认为不同。考虑这样影响的只是一堆指针移动操作,所以不妨在位移的时候不直接计入 即可。
复杂度 。
#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
首先正难则反,显然 在所有串中的出现次数是 。
要求的是没有长度为 的每个数字只出现一次的区间。求这样的区间中 出现次数。
如果 本来就是 colorful 的,显然就是 。
如果 两两不同,可以发现 的实际数值对答案没有影响,只需要求出没有有长度为 的出现次数然后除以总个数即可。
如果 存在相同,那么取第一个相同的位置与最后一个相同的位置即可。剩下就是一个卷积了。
复杂度 。
#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!
首先可以发现如果 位置发生了一次交换,那么可以证明 位置就不能被移动了。
所以交换中心一定有 。
令 ,那么 的连续值之间切开,可以将序列分成若干段。对于每段,首先值域必须完全符合该段左右端点,其次必须有最长下降子序列不超过 。
直接贪心求两遍上升子序列即可。
复杂度 。
#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;
}
本文来自博客园,作者:Flying2018,转载请注明原文链接:https://www.cnblogs.com/Flying2018/p/arc098-102.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 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编程运行原理