2023 春测

涂色游戏 Paint

题意

有一个 n×m 的矩阵。现在进行 q 次操作,第 i 次操作将某行/某列的所有元素赋为 ci,求所有操作之后的矩阵。T 组数据。nm,q106

解法

显然对于第 i 行第 j 列的元素,只需要讨论对第 i 行和第 j 列最后一次的赋值即可。

代码

点此查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=100010;
int T,n,m,q,i,j,o,x,c;
int t[2][maxn],f[2][maxn];
int main(){
freopen("paint.in","r",stdin);
freopen("paint.out","w",stdout);
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&m,&q);
for(i=1;i<=q;++i){
scanf("%d%d%d",&o,&x,&c);
t[o][x]=i; f[o][x]=c;
}
for(i=1;i<=n;++i){
x=t[0][i]; c=f[0][i];
for(j=1;j<=m;++j) printf("%d ",t[1][j]>x?f[1][j]:c);
putchar('\n');
}
memset(t[0]+1,0,n<<2); memset(f[0]+1,0,n<<2);
memset(t[1]+1,0,m<<2); memset(f[1]+1,0,m<<2);
}
return 0;
}

幂次 Power

题意

1n 内能被表示成 ab 的形式的数的数量,其中 a,bN+;bkn1018,k100

解法

特判 1,然后对于某个 abc|bab 一定可以表示成 (abc)c 的形式,容斥即可。

代码

点此查看代码
#include <bits/stdc++.h>
using namespace std;
int k,i,j,p;
long long n,l,r,m,c,a,s,b[80];
int main(){
freopen("power.in","r",stdin);
freopen("power.out","w",stdout);
scanf("%lld%d",&n,&k);
if(k==1){
printf("%lld",n);
return 0;
}
for(i=70;i>=k;--i){
for(l=1,r=n;l<=r;){
m=(l+r)>>1;
for(p=i,c=1;p;--p){
if(c>n/m) break;
c*=m;
}
if(p) r=m-1;
else a=m,l=m+1;
}
for(j=i+i,--a;j<=70;j+=i) a-=b[j];
b[i]=a; s+=a;
}
printf("%lld",s+1);
return 0;
}

圣诞树 Tree

题意

有一个 n 个点的凸多边形,第 i 个顶点为 (xi,yi)。现在需要在纵坐标最大且编号最小的点 k 出发遍历其他所有点,满足路径长度最小。输出某种合法的遍历顺序。n103;|xi|,|yi|107

解法

考虑最后形成的路径一定不会存在交叉的情况,否则对于某条自交的路径一定可以调整为起终点相同的不自交路径,且由于三角形两边之和大于第三边可得调整后一定更优。

此时某条路径经过的点一定是一段段连续的区间(否则从区间外的点连向区间内一定会形成交点),所以从某个点出发能走到的点一定只能是区间两端的点。然后就可以使用区间 dp 计算答案了。

代码

点此查看代码
#include <bits/stdc++.h>
using namespace std;
#define ld long double
const int maxn=1010;
const int maxb=2010;
int n,i,j,k,l,r,b,p[maxn];
ld xs,xt,ys,yt,x[maxn],y[maxn];
ld d[maxb][maxb],dp[maxb][maxb][2];
inline void cmin(ld &x,ld y){if(x>y) x=y;}
int main(){
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
scanf("%d",&n); b=(n<<1)-1;
for(i=1;i<=b;++i) for(j=1;j<=b;++j) dp[i][j][0]=dp[i][j][1]=1e18;
for(i=k=1;i<=n;++i){
scanf("%Lf%Lf",x+i,y+i);
if(y[i]>y[k]) k=i;
}
for(i=1;i<=n;++i){
xs=x[i]; ys=y[i];
for(j=1;j<=n;++j){
if(i==j) continue; xt=xs-x[j]; yt=ys-y[j];
d[i][j]=d[i+n][j]=d[i][j+n]=d[i+n][j+n]=sqrtl(xt*xt+yt*yt);
}
}
dp[k][k][0]=dp[n+k][n+k][0]=0;
for(i=1;i<n;++i){
for(l=1,r=i;r<=b;++l,++r){
if(l!=1) cmin(dp[l-1][r][0],min(dp[l][r][0]+d[l-1][l],dp[l][r][1]+d[l-1][r]));
if(r!=b) cmin(dp[l][r+1][1],min(dp[l][r][0]+d[r+1][l],dp[l][r][1]+d[r+1][r]));
}
}
for(i=l=r=1;i<=n;++i){
if(dp[i][i+n-1][0]<dp[l][l+n-1][r]) l=i,r=0;
if(dp[i][i+n-1][1]<dp[l][l+n-1][r]) l=i,r=1;
}
for(i=n,p[n]=l+(n-1)*r;i>1;--i,p[i]=l+(i-1)*r){
if(r) r=(dp[l][l+i-2][1]+d[l+i-2][l+i-1]<dp[l][l+i-2][0]+d[l][l+i-1]);
else r=(dp[l+1][l+i-1][1]+d[l+i-1][l]<dp[l+1][l+i-1][0]+d[l+1][l]),++l;
}
for(i=1;i<=n;++i) printf("%d ",(p[i]-1)%n+1);
return 0;
}

密码锁 Lock

题意

有一个 k×n 的矩阵 a。可以进行任意次操作,每次操作选择某个 i,然后 j[1,k],将 aj,i 赋为 ajmodk+1,i。求经过若干操作后能得到的 aminmaxj=1k(maxi=1naj,imini=1naj,i)T 组数据。ai,j3×104;k4;k3n1.5×105;k=4n3×104

解法

k=1 时直接输出 maxai,jminai,j

k=2 时考虑 maxai,jminai,j 不能在同一行(否则答案一定会取到最大值),且对于 k 更大时该结论同样成立。此时可以将其他的 a1,i,a2,i 的较大者换到 max 所在行,将较小者换到 min 所在行就可以同时达成最大化 max 所在行的最小值同时最小化 min 所在行的最大值。

k=3 时考虑在确定好 maxmin 所在行时(有 O(k) 种取值),maxmin 对应列在其他行的取值固定。然后考虑二分答案,设当前在确定答案是否大于 M,则需要让其他列在 maxmin 所在行取值满足要求,同时需要存在第三行的某种取值方式使得所有列在第三行的取值均在某段长为 M 的区间内。此时可以把每种取值看成将区间左端点限制在某个范围内,可以看成有没有区间颜色数量为 n,使用双指针维护即可。

k=4 时仍然可以沿用上面的思路,但是需要所有列在第三行和第四行的取值均在某段长为 M 的区间内;将对应的取值化为平面直角坐标系上的点则问题变成了需要让所有种取值均在某个 M×M 的矩形内。考虑将每列对应的矩形分别求并(可以使用单次 O(2k) 的做法),然后用扫描线 + 线段树维护对应的并集,则线段树上只需要进行 O(nk) 次区间修改。

代码(暂缺)

点此查看代码
posted @   Fran-Cen  阅读(51)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示