2025.8.11 CSP-S模拟赛33
获得了极其惨烈的40分
T1 机器人
简单dfs,不知道考场上为什么死活调不出来,以至于极大影响了心态,这确实是我的严重失误,后面忘了;
一个坐标有走过,没有走过两种状态,没有走过又分有障碍和没障碍两种情况,注意细节即可;
#include<bits/stdc++.h>
using namespace std;
int n;char c[25];
struct node{
int x,y;
};
bool cmp(node a,node b){
return (a.x^b.x?a.x<b.x:a.y<b.y);
}
vector<node> ans;
int flag[105][105],za[105][105];
int jz[105][105];
void dfs(int xb,int x,int y){
if(xb>n){
if(!jz[x][y])
ans.push_back(node{x-50,y-50});
jz[x][y]=1;
return ;
}
flag[x][y]=1;
int nx=x,ny=y;
if(c[xb]=='L') nx--;
if(c[xb]=='R') nx++;
if(c[xb]=='D') ny--;
if(c[xb]=='U') ny++;
if(flag[nx][ny]!=1){
int lst=flag[nx][ny];
flag[nx][ny]=2;
dfs(xb+1,x,y);
flag[nx][ny]=lst;
}
if(flag[nx][ny]!=2){
int lst=flag[nx][ny];
flag[nx][ny]=1;
dfs(xb+1,nx,ny);
flag[nx][ny]=lst;
}
return ;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++) cin>>c[i];
dfs(1,50,50);
cout<<ans.size()<<"\n";
sort(ans.begin(),ans.end(),cmp);
for(int i=0;i<ans.size();i++){
cout<<ans[i].x<<" "<<ans[i].y<<"\n";
}
return 0;
}
T2 旅行
第一次接触基环树,考场上没有什么思路,体现出知识点的重要性;
我们发现每次更改一条边时,真正改变的答案数量时极其有限的,我们假设把一条边的颜色由 \(a\) 更改为 \(b\) ,如果这条边两端的节点均连接一条除此边之外的颜色为 \(x\) 的边,称这条边两头都有颜色 \(x\),反之同理;
我们可以发现:
1、这条边两头都有 \(a\) ,就把原来的一个联通块断成两个,那么 \(ans+=1\) ;
2、这条边两头都没有 \(a\) ,就减少了自己这个颜色为 \(a\) 的联通块,那么 \(ans-=1\) ;
3、这条边两头都有 \(b\) ,就把原来的两个联通块连成一个,那么 \(ans-=1\) ;
4、这条边两头都没有 \(b\) ,就增加了自己这个颜色为 \(b\) 的联通块,那么 \(ans+=1\) ;
因为是基环树,所以要特殊处理环上的边;如果环上除了这条边以外颜色均为 \(a\) ,那么可以忽略第一、第二条;同样的,如果环上除了这条边以外颜色均为 \(b\) ,那么可以忽略第三、第四条,证明都是显然的 ;
对于基环树找环,可以看dzb大佬的博客,写的非常好;
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
const unsigned long long p=13331;
int T,n,m,ans;
int d[MAXN],cnt[MAXN];
int fa[MAXN],dep[MAXN],lst[MAXN];
struct nd{
int pos,col,id;
};
vector<nd> e[MAXN];
map<int,int> mp[MAXN];
struct node{
int x,y,col;
}eg[MAXN<<1];
void dfs(int x,int lst,int col){
cnt[x]++;
if(cnt[x]>d[x]) return ;
for(int i=0;i<e[x].size();i++){
int y=e[x][i].pos;
if(y==lst) continue;
if(e[x][i].col==col){
ans--;
dfs(y,x,col);
}
else{
dfs(y,x,e[x][i].col);
}
}
return ;
}
int flag[MAXN],ins[MAXN],mark[MAXN],stk[MAXN],vis[MAXN],top;
int rt;
int find(int x){
return (x==fa[x]?x:fa[x]=find(fa[x]));
}
void add(int x,int y){
x=find(x),y=find(y);
if(x!=y){
fa[y]=x;
ans--;
}
}
void dfs_tr(int x,int fa){
if(ins[x]){
rt=x;
int v;
mark[x]=1;
while(stk[top]!=x){
mark[stk[top]]=1;
top--;
}
return ;
}
if(vis[x]==1) return ;
stk[++top]=x;
vis[x]=ins[x]=1;
for(int i=0;i<e[x].size();i++){
int y=e[x][i].pos;
if(y==fa) continue;
dfs_tr(y,x);
}
top--;
ins[x]=0;
return ;
}
void dfs_eg(int x,int fa){
if(x==rt) return ;
for(int i=0;i<e[x].size();i++){
int y=e[x][i].pos;
if(y==fa) continue;
if(mark[y]){
flag[e[x][i].id]=1;
dfs_eg(y,x);
}
}
return ;
}
map<int,int> bh[MAXN];
map<int,int> t;
int len;
int main(){
// freopen("tour1.in","r",stdin);
// freopen("tour.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>T;
while(T--){
cin>>n>>m;ans=n;top=0;
for(int i=1;i<=n;i++){
int x,y,z;cin>>x>>y>>z;
bh[x][y]=bh[y][x]=i;
e[x].push_back((nd){y,z,i});
e[y].push_back((nd){x,z,i});
mp[x][z]++,mp[y][z]++;
eg[i].x=x,eg[i].y=y,eg[i].col=z;
}
for(int i=1;i<=n;i++){
fa[i]=i;
}
for(int x=1;x<=n;x++){
for(int j=0;j<e[x].size();j++){
lst[e[x][j].col]=0;
}
for(int j=0;j<e[x].size();j++){
if(lst[e[x][j].col]) add(lst[e[x][j].col],e[x][j].id);
lst[e[x][j].col]=e[x][j].id;
}
}
// cout<<"ans: "<<ans<<"\n";
dfs_tr(1,0);
// for(int i=1;i<=n;i++) if(mark[i]) cout<<i<<" ";
// cout<<"\n";
for(int i=1;i<=n;i++) t[i]=0;
for(int i=0;i<e[rt].size();i++){
if(mark[e[rt][i].pos]){
flag[e[rt][i].id]=1;
dfs_eg(e[rt][i].pos,rt);
break;
}
}
len=0;
// for(int i=1;i<=n;i++) if(mark[i]) cout<<i<<"\n";
for(int i=1;i<=n;i++){
if(flag[i]) t[eg[i].col]++,len++;
// cout<<i<<": "<<flag[i]<<"\n";
}
// cout<<"len: "<<len<<"\n";
for(int i=1;i<=m;i++){
int x,y,z;cin>>x>>y>>z;
int _id=bh[x][y];
mp[x][eg[_id].col]--,mp[y][eg[_id].col]--;
if(flag[_id]) t[eg[_id].col]--;
if(!flag[_id]||(flag[_id]&&t[eg[_id].col]<len-1)){
if(mp[x][eg[_id].col]>0&&mp[y][eg[_id].col]>0) ans+=1;
if(mp[x][eg[_id].col]==0&&mp[y][eg[_id].col]==0) ans-=1;
}
if(!flag[_id]||(flag[_id]&&t[z]<len-1)){
if(mp[x][z]>0&&mp[y][z]>0) ans-=1;
if(!mp[x][z]&&!mp[y][z]) ans+=1;
}
if(flag[_id]) t[z]++;
mp[x][z]++,mp[y][z]++;
eg[_id].col=z;
cout<<ans<<"\n";
}
for(int i=1;i<=n;i++) bh[i].clear(),mp[i].clear(),e[i].clear();
for(int i=1;i<=n;i++) flag[i]=ins[i]=vis[i]=mark[i]=0;
}
return 0;
}
T3 点餐
依旧是没有学过的,正解是可持久化线段树,为此去打了板子,不过感觉还是没有理解透彻;
我们将菜品按 \(b\) 从小到大排序,然后枚举 \(x\) 作为断点,那么 \(b_X\) 必然为最大的 \(b\) ,问题就变成了在前 \(x-1\) 个菜品中寻找 \(k-1\) 个 \(a_i\) 和最小的,这一过程可以用可持久化线段树维护前缀最小值,记为 \(w(k,x)\)。
对于两个不同的决策 \(x,y(x<y)\) ,若 \(w(k,y) \leq w(k,x)\) 那么随着 \(k\) 的增加,因为 \(y\) 的选择范围严格包含了 \(x\) 的选择范围,所以 \(y\) 的新方案一定不会劣于 \(x\) 的新方案,因此可以证明具有决策单调性,可以分治求解;
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN=2e5+10;
int n,lsh[MAXN],t[MAXN],tot;
int root[MAXN];
int ans[MAXN];
struct node{
int a,b;
}p[MAXN];
bool cmp(node a,node b){
return (a.b^b.b?a.b<b.b:a.a<b.a);
}
struct zx_tree{
int lc,rc,sum,siz;
}tr[MAXN<<5];
void build(int &id,int l,int r){
id=++tot;
tr[id].siz=1;
if(l==r) return ;
int mid=l+r>>1;
build(tr[id].lc,l,mid);
build(tr[id].rc,mid+1,r);
tr[id].siz=tr[tr[id].lc].siz+tr[tr[id].rc].siz+1;
return ;
}
void add(int id,int &k,int l,int r,int val){
k=++tot;
if(l==r){
tr[k].sum=lsh[val],tr[k].siz=1;
return ;
}
int mid=l+r>>1;
if(val<=mid){
tr[k].rc=tr[id].rc;
add(tr[id].lc,tr[k].lc,l,mid,val);
}
else{
tr[k].lc=tr[id].lc;
add(tr[id].rc,tr[k].rc,mid+1,r,val);
}
tr[k].siz=tr[tr[k].lc].siz+tr[tr[k].rc].siz;
tr[k].sum=tr[tr[k].lc].sum+tr[tr[k].rc].sum;
return ;
}
int query(int id,int l,int r,int val){
if(!id||!val) return 0;
if(tr[id].siz==val) return tr[id].sum;
int mid=l+r>>1;
if(val<=tr[tr[id].lc].siz) return query(tr[id].lc,l,mid,val);
else return tr[tr[id].lc].sum+query(tr[id].rc,mid+1,r,val-tr[tr[id].lc].siz);
}
void solve(int L,int R,int l,int r){
if(L>R) return ;
int mid=L+R>>1;
int &res=ans[mid]=1e18,px=-1;
for(int i=max(l,mid);i<=r;i++){
int q=query(root[i-1],1,n,mid-1)+lsh[p[i].a]+p[i].b;
if(q<res){
res=q,px=i;
}
}
solve(L,mid-1,l,px);
solve(mid+1,R,px,r);
return ;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>p[i].a>>p[i].b;
lsh[i]=p[i].a;
}
sort(lsh+1,lsh+n+1);
for(int i=1;i<=n;i++){
int xb=lower_bound(lsh+1,lsh+n+1,p[i].a)-lsh;
p[i].a=xb+t[xb];t[xb]+=1;//离散化
}
sort(p+1,p+n+1,cmp);
for(int i=1;i<=n;i++){
add(root[i-1],root[i],1,n,p[i].a);
}
solve(1,n,1,n);
for(int i=1;i<=n;i++)
cout<<ans[i]<<"\n";
return 0;
}
T4 点餐
依旧不会
本文来自博客园,作者:zhangch_qwq,转载请注明原文链接:https://www.cnblogs.com/zhangchenhua-awa/p/19035764

浙公网安备 33010602011771号