【比赛记录】2025CSP-S模拟赛22
| A | B | C | D | Sum | Rank |
|---|---|---|---|---|---|
| 80 | 0 | 15 | - | 95 | 7/21 |
A. 草莓列车(train)
我们需要 \(O(1)\) 修改的数据结构,这让我们联想到考虑把 ST 表倒过来做。于是做法就很显然了,将修改区间拆成两个区间赋值,最后再 \(O(n\log n)\) 下传即可。
剩下的全在代码里了:
Code
SB 数据 a 根本不是 1e5,m 也根本不是 1e7
#include<bits/stdc++.h>
#define ll long long
#define il inline
#define ui unsigned int
using namespace std;
namespace asbt{
const int maxn=1e5+5;
int n,m,T,Log[maxn];
ui st[maxn][22];
namespace Maker{
ui x0,seed;
il void init() {cin>>x0>>seed;}
il ui getnum(){
x0=(x0<<3)^x0;
x0=((x0>>5)+seed)^x0;
return x0;
}
}
int main(){
// system("fc train2.out my.out");
// freopen("train2.in","r",stdin);
// freopen("my.out","w",stdout);
ios::sync_with_stdio(0),cin.tie(0);
cin>>n>>m>>T;
for(int i=2;i<=n;i++){
Log[i]=Log[i>>1]+1;
}
// for(int i=1;i<=n;i++){
// cout<<Log[i]<<" ";
// }
// puts("");
for(int i=1;i<=n;i++){
cin>>st[i][0];
}
Maker::init();
for(int i=1; i<=m; ++i){
int l=Maker::getnum()%n+1,r=Maker::getnum()%n+1;
ui v=Maker::getnum();
if(l>r) swap(l,r);
if(T==1) l=1;
int p=Log[r-l+1];
ui &t1=st[l][p],&t2=st[r-(1<<p)+1][p];
t1=max(t1,v),t2=max(t2,v);
}
for(int j=Log[n];j;j--){
for(int i=1;i+(1<<j)-1<=n;i++){
ui &t1=st[i][j-1],&t2=st[i+(1<<(j-1))][j-1];
t1=max(t1,st[i][j]),t2=max(t2,st[i][j]);
}
}
for(int i=1;i<=n;i++){
cout<<st[i][0]<<" ";
}
return 0;
}
}
int main(){return asbt::main();}
B. 草莓路径(path)
C. 草莓城市(city)
考虑二分,注意到此时对于每个点都有四种状态,于是这是一个 4-sat 问题。进一步发现这四个三角形都是由两个小三角形组成的,也就是左上的小三角形和右下的选一个,左下的和右上的选一个,于是变成 2-sat 问题。
于是此时问题变为如何判断两个三角形是否相交。可以想到一个充要条件是至少有两条边相交(当然此时有 bug,如果两个三角形重合那么会被判作不相交,这种情况特判即可)。那么这个其实是简单的,如果线段 \(AB\) 与线段 \(CD\) 相交,那么有:
也就是说,\(C\) 和 \(D\) 分布在 \(AB\) 的两侧。于是遍历三角形的边即可。
Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
#define pb push_back
using namespace std;
namespace asbt{
const int maxn=1e3+5;
const double eps=1e-4;
int n,m,kk,xx[205],yy[205],tot,hao[205][2][2];
int cnt,top,scn,dfn[maxn],low[maxn],stk[maxn],scc[maxn];
bool ins[maxn];
vector<int> e[maxn];
struct vec{
double x,y,z;
vec(double x=0,double y=0,double z=0):x(x),y(y),z(z){}
il vec operator+(const vec &p)const{
return vec(x+p.x,y+p.y,z+p.z);
}
il vec operator-(const vec &p)const{
return vec(x-p.x,y-p.y,z-p.z);
}
il double operator^(const vec &p)const{ // 点乘
return x*p.x+y*p.y+z*p.z;
}
il vec operator*(const vec &p)const{ // 叉乘
return vec(y*p.z-z*p.y,z*p.x-x*p.z,x*p.y-y*p.x);
}
};
struct sjx{
vec a,b,c;
il bool xj(const sjx &p)const{
#define xj(a1,b1,a2,b2) ((((a2-a1)*(b1-a1))^((b2-a1)*(b1-a1)))<0&&(((a1-a2)*(b2-a2))^((b1-a2)*(b2-a2)))<0)
return xj(a,b,p.a,p.b)||xj(a,b,p.b,p.c)||xj(a,b,p.c,p.a)||xj(b,c,p.a,p.b)||xj(b,c,p.b,p.c)||xj(b,c,p.c,p.a)||xj(c,a,p.a,p.b)||xj(c,a,p.b,p.c)||xj(c,a,p.c,p.a);
#undef xj
}
}dyk[205][2][2];
il void tarjan(int u){
dfn[u]=low[u]=++cnt,stk[++top]=u,ins[u]=1;
for(int v:e[u]){
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(ins[v]){
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u]){
int v=0;
scn++;
do{
v=stk[top--];
ins[v]=0,scc[v]=scn;
}while(v!=u);
}
}
int main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>n>>m>>kk;
for(int i=1;i<=kk;i++){
cin>>xx[i]>>yy[i];
hao[i][0][0]=++tot; // 左上
hao[i][0][1]=++tot; // 右下
hao[i][1][0]=++tot; // 左下
hao[i][1][1]=++tot; // 右上
}
double l=0,r=1e9;
while(r-l>eps){
double mid=(l+r)/2,t=mid/2;
for(int i=1;i<=kk;i++){
dyk[i][0][0].a=dyk[i][0][1].a=dyk[i][1][0].a=dyk[i][1][1].a=vec(xx[i],yy[i]);
dyk[i][0][0].b=dyk[i][1][0].b=vec(xx[i]-t,yy[i]);
if(xx[i]-t<0){
e[hao[i][0][0]].pb(hao[i][0][1]);
e[hao[i][1][0]].pb(hao[i][1][1]);
}
dyk[i][0][1].b=dyk[i][1][1].b=vec(xx[i]+t,yy[i]);
if(xx[i]+t>n){
e[hao[i][0][1]].pb(hao[i][0][0]);
e[hao[i][1][1]].pb(hao[i][1][0]);
}
dyk[i][0][0].c=dyk[i][1][1].c=vec(xx[i],yy[i]+t);
if(yy[i]+t>m){
e[hao[i][0][0]].pb(hao[i][0][1]);
e[hao[i][1][1]].pb(hao[i][1][0]);
}
dyk[i][0][1].c=dyk[i][1][0].c=vec(xx[i],yy[i]-t);
if(yy[i]-t<0){
e[hao[i][0][1]].pb(hao[i][0][0]);
e[hao[i][1][0]].pb(hao[i][1][1]);
}
}
for(int i=1;i<=kk;i++){
for(int j=i+1;j<=kk;j++){
if(xx[i]==xx[j]&&yy[i]==yy[j]){
for(int x:{0,1}){
for(int y:{0,1}){
e[hao[i][x][y]].pb(hao[j][x][y^1]);
e[hao[j][x][y]].pb(hao[i][x][y^1]);
}
}
}
for(int x1:{0,1}){
for(int y1:{0,1}){
for(int x2:{0,1}){
for(int y2:{0,1}){
if(dyk[i][x1][y1].xj(dyk[j][x2][y2])){
e[hao[i][x1][y1]].pb(hao[j][x2][y2^1]);
e[hao[j][x2][y2]].pb(hao[i][x1][y1^1]);
}
}
}
}
}
}
}
cnt=top=scn=0;
for(int i=1;i<=tot;i++){
if(!dfn[i]){
tarjan(i);
}
}
for(int i=1;i<=kk;i++){
for(int j:{0,1}){
if(scc[hao[i][j][0]]==scc[hao[i][j][1]]){
r=mid;
goto togo;
}
}
}
l=mid;
togo:;
for(int i=1;i<=tot;i++){
dfn[i]=low[i]=scc[i]=ins[i]=0;
e[i].clear();
}
}
printf("%.2f",l);
return 0;
}
}
int main(){return asbt::main();}
D. 草莓之歌(easy)
设 \(f_{i,j}\) 表示 \(i\) 为第 \(j\) 段的末尾的最小交换次数,考虑从 \(f_{k,j-1}\) 到 \(f_{i,j}\) 的转移,我们需要将第 \(k+1\) 到第 \(i\) 个 \(B\) 都移动到第 \(i\) 个 \(A\) 后面,于是有转移:\(f_{i,j}=\min_{k=0}^{i-1}f_{k,j-1}+\sum_{x=k+1}^{i}\max(a_x-k,0)\),其中 \(a_x\) 表示第 \(x\) 个 \(A\) 前面 \(B\) 的数量。看到要求分 \(k\) 段这样的限制,不妨考虑 wqs 二分,可以发现 \(f_{i,j}\) 关于 \(j\) 是一个下凸函数。于是 DP 变成 \(f_i=f_j-mid+\sum_{k=j+1}^{i}\max(a_k-j,0)\)。设 \(b_j\) 表示 \(j\) 右边第一个满足 \(a_k\ge j\) 的 \(k\),再给 \(a\) 做个前缀和,于是转移变成 \(f_i=f_j+sa_i-sa_{b_j-1}-j\times(i-b_j+1)-mid\),斜率优化即可。时间复杂度线性对数。
Code
#include<bits/stdc++.h>
#define int long long
#define il inline
#define lwrb lower_bound
#define pb push_back
using namespace std;
namespace asbt{
const int maxn=1e6+5;
int n,m,tot,cnt,a[maxn],b[maxn],f[maxn],g[maxn],q[maxn];
string s;
vector<int> c[maxn];
il bool check(int x){
int hd=1,tl=0;
#define X(i) (i)
#define Y(i) (f[i]-a[b[i]-1]+i*b[i]-i)
#define K(i,j) ((Y(j)-Y(i))*1.0l/(X(j)-X(i)))
for(int i=1;i<=n;i++){
for(int j:c[i]){
while(hd<tl&&K(q[tl-1],q[tl])>K(q[tl],j)){
tl--;
}
q[++tl]=j;
}
while(hd<tl&&K(q[hd],q[hd+1])<i){
hd++;
}
f[i]=f[q[hd]]+a[i]-a[b[q[hd]]-1]-q[hd]*(i-b[q[hd]]+1)-x;
g[i]=g[q[hd]]+1;
}
#undef X
#undef Y
#undef K
return g[n]<=m;
}
int main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>n>>m>>s;
s=" "+s;
for(int i=1;i<=n<<1;i++){
if(s[i]=='A'){
a[++cnt]=tot;
}
else{
tot++;
}
}
for(int i=0;i<=n;i++){
b[i]=lwrb(a+i+1,a+n+1,i)-a;
c[b[i]].pb(i);
}
for(int i=1;i<=n;i++){
a[i]+=a[i-1];
}
int l=-1e12,r=0;
while(l<r){
int mid=(l+r+1)>>1;
if(check(mid)){
l=mid;
}
else{
r=mid-1;
}
}
check(l);
// cout<<l<<'\n';
cout<<f[n]+m*l;
return 0;
}
}
signed main(){return asbt::main();}

浙公网安备 33010602011771号