AtCoder Grand Contest 030
链接
C. Coloring Torus
构造题。
考虑如果 ,那么直接构造 这样的矩阵即可。
但是这种做法不太方便扩展。考虑另一种构造,即构造 这样的拉丁方。
这样有什么好处,就是奇数行与偶数行被完全分开了,我任意将奇数行的某个数字全部替换成另一个没有出现的数字,得到的矩阵仍然合法。
这样构造的上界是 ,恰好满足条件。
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 3010
#define mod 1000000007
using namespace std;
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;
}
const int iv2=ksm(2);
int f[N][N],a[N];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) if(a[i]>a[j]) f[i][j]=1;
for(int t=1;t<=m;t++)
{
int x,y;scanf("%d%d",&x,&y);
f[x][y]=f[y][x]=1ll*(f[x][y]+f[y][x])*iv2%mod;
for(int i=1;i<=n;i++) if(i!=x && i!=y) f[y][i]=f[x][i]=1ll*(f[x][i]+f[y][i])*iv2%mod,f[i][x]=f[i][y]=1ll*(f[i][x]+f[i][y])*iv2%mod;
}
int ans=0;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++) ans=(ans+f[i][j])%mod;
printf("%lld ",1ll*ans*ksm(2,m)%mod);
return 0;
}
D. Inversion Sum
考虑一个很显然的想法是贡献单独计算,即对于每一对 ,计算它产生逆序对的贡献。但直接这样计算很麻烦,处理不精细就变成 的。
再考虑另一个转化,即每次交换看作有 交换,最后算期望。这样就不用处理是否交换导致的 问题。
那么考虑一对 会影响的整数对有哪些,显然只有 共 个。而这样处理后还有一个好处:就是 之间之前的相对关系无所谓了,即直接有 。
总复杂度 。
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 3010
#define mod 1000000007
using namespace std;
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;
}
const int iv2=ksm(2);
int f[N][N],a[N];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) if(a[i]>a[j]) f[i][j]=1;
for(int t=1;t<=m;t++)
{
int x,y;scanf("%d%d",&x,&y);
f[x][y]=f[y][x]=1ll*(f[x][y]+f[y][x])*iv2%mod;
for(int i=1;i<=n;i++) if(i!=x && i!=y) f[y][i]=f[x][i]=1ll*(f[x][i]+f[y][i])*iv2%mod,f[i][x]=f[i][y]=1ll*(f[i][x]+f[i][y])*iv2%mod;
}
int ans=0;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++) ans=(ans+f[i][j])%mod;
printf("%lld ",1ll*ans*ksm(2,m)%mod);
return 0;
}
E. Less than 3
很妙的题。
考虑如果认为 之间有一条红线, 之间有一条蓝线,那么最后序列一定是红蓝线交错。不妨假设开头结尾有无数条红蓝线交错的线,如:
显然如果两个式子的红蓝线完全匹配,那么这两个序列是全等的。
由于每次操作不可能增加或减少红蓝线数量,所以每次操作等价于将一条线移动一格。开头操作视为将开头的末尾线段移动到第一格后。并且时刻要求相邻两条线段之间最多差 2 格。
可以发现交叉匹配一定不优,所有排完序后一定是按顺序匹配。答案即距离之和。
只需要枚举匹配第一个线段的线段是哪一条即可。复杂度 。
注意要保证匹配线段的颜色相同。
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 5010
using namespace std;
char s[N],t[N];
int x[N],xt,y[N],yt,n;
int get(int a[],int at,int i){return i<0?0:i>at?n:a[i];}
int main()
{
scanf("%d",&n);
scanf("%s%s",s+1,t+1);
for(int i=1;i<n;i++){if(s[i]!=s[i+1]) x[++xt]=i;if(t[i]!=t[i+1]) y[++yt]=i;}
int ans=n*n,m=xt+yt;
for(int i=(xt&1)^(s[1]!=t[1]);i<=m+1;i+=2)
{
int res=0;
for(int j=-m;j<=m;j++) res+=abs(get(x,xt,j)-get(y,yt,i-xt+j));
ans=min(ans,res);
}
printf("%d\n",ans);
return 0;
}
F. Permutation and Minimum
考虑分类,显然只要将 三组分开,最后乘上 组的阶乘,剩下的部分就与相对顺序无关了。
考虑从大到小枚举数字,这样的好处是:如果它匹配了一个填了一半的组,那么这个组的最小值就是它,否则如果将一个空组填了一般,那么最小值一定不是它。
用 表示当前要填 ,当前有 个填了一半的 组,有 个已经填了的 组。
如果 属于 组,那么什么都不干。
如果 属于 组,那么可以新开一个 ,可以填一个 组 ,可以填一个 组 。
如果 属于 组,那么可以新开一个 ,可以填一个 组 。
复杂度 。
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 310
#define mod 1000000007
using namespace std;
int f[2][N][N],a[N*2];//f[i][j][k]:填到 i,有 j 对填了一半的 -1,-1,k 对未匹配的 a,-1
short vis[N*2];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=2*n;i++) scanf("%d",&a[i]);
int tt=0;
for(int i=1;i<=2*n;i+=2)
if(~a[i] && ~a[i+1]) vis[a[i]]=vis[a[i+1]]=2;
else if(~a[i] || ~a[i+1]) vis[a[i]+a[i+1]+1]=1;
else ++tt;
f[0][1][1]=1;
for(int i=2*n;i;i--)if(vis[i]!=2)
{
swap(f[0],f[1]),memset(f[0],0,sizeof(f[0]));
auto g=f[0];
for(int j=1;j<=n+1;j++)
for(int k=1;j+k<=n+2;k++)
if(f[1][j][k])
{
int v=f[1][j][k];
if(vis[i]==1) g[j-1][k]=(g[j-1][k]+v)%mod,g[j][k+1]=(g[j][k+1]+v)%mod;
else g[j-1][k]=(g[j-1][k]+v)%mod,g[j][k-1]=(g[j][k-1]+1ll*v*(k-1))%mod,g[j+1][k]=(g[j+1][k]+v)%mod;
}
}
int res=f[0][1][1];
for(int i=1;i<=tt;i++) res=1ll*res*i%mod;
printf("%d",res);
return 0;
}
【推荐】国内首个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编程运行原理