2022.4.10普及组模拟

A 排座位

没有任何难度的大水题

想复杂了。如果只能是两个相邻的位置交换自然要求逆序对,但是这个题可以随便换,所以我们乱搞。最终的目标就是把 1 换到第一个位置, 2 换到第二个位置,以此类推

如果 datai=i 就不操作,如果 datai!=idatapos=i 则交换。很显然的做法,但是乍一看貌似无法保证交换次数最小,所以有另一个很严谨的做法

Code

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000000+5;
inline int read(){
	int x=0;char c=getchar();
	while(c<'0'||c>'9')c=getchar();
	while(c>='0'&&c<='9'){
		x=(x<<1)+(x<<3)+(c^'0');c=getchar();
	}
	return x;
}
int data[maxn],pos[maxn];
int n;
int main(){
	freopen("seat.in","r",stdin);
	freopen("seat.out","w",stdout);
	n=read();
	for(int i=1;i<=n;++i){
		data[i]=read();
		pos[data[i]]=i;
	}
	int ans=0;
	for(int i=1;i<=n;++i){
	    if(data[i]!=i){
		    pos[data[i]]=pos[i];
	    	swap(data[i],data[pos[i]]);
		    ans++;
		}
	}
	printf("%d\n",ans);
	return 0;
}

B 梦中的学校(原题金字塔,《算法竞赛进阶指南》区间DP部分)

对于一个字符串 SlSr可能会有多种情况,所以考虑区间DP。定义状态 fi,jSlSr 的情况数。

我们只考虑其构成一颗树的情况,所以 Sl!=Sr 的情况是不合法,dfs肯定要从根进去再从根出来。

如果 l=r 很显然方案数为1

为了不重复计数,只考虑该范围中第一颗子树的范围,枚举断点 klr 被分为 l+1k1kr1两部分,k 不相同,第一颗子树大小也就不相同,就不可能产生重复的结构,则有方程

fi,j=fi,j+fi+1,k1fk,j1

状态之间遵循加法原理而子状态之间遵循乘法原理

Code

int solve(int l,int r){
    if(l>r)return 0;
    if(S[l]!=S[r])return f[l][r]=0;
    if(l==r)return f[l][r]=1;
    if(f[l][r]!=-1)return f[l][r];
    f[l][r]=0;
    for(int k=l+2;k<=r;++k){
        f[l][r]=(f[l][r]+1ll*solve(l+1,k-1)*solve(k,r))%mod;
    }
    return f[l][r];
}
printf("%d\n",solve(1,strlen(S+1)));

C 激流突进(SCOI2011糖果)

显然是一个差分约束系统

如果u>v,则<u,v>=1

如果u<v,则<v,u>=1

如果u=v,则<u,v>=<u,v>=0

如果u<=v,则<v,u>=0

如果u>=v,则<u,v>=0

如果A>B>C,则<B,A>=<C,B>=<C,A>=1,为了使结果正确,建完图之后跑最长路。

建完图之后很有可能不完全,设一个解X0=0,由于其他的解都是正解,很显然有i[1,n],都有Xi>=X0,即XiX0>=0,0向所有的点连一条权值为0的边即可

不成立的情况:

如果A>B,B>C,C>A,显然不成立,而且建图后出现环,可以用topo排序处理。最长路算法常用spfa,且spfa跑最长路可以判正环,所以用spfa处理

如果A>A 或 A<A ,显然不成立

这样处理完之后貌似就没什么问题,但是除了正环以外还有另外一种环,A=B=C,边权都为0,所以spfa扫它没啥意义,所以连完1,3,5三种情况后Tarjan缩点,再连2,4情况的边

struct Graph{
    struct edge{
        int to,next,dis;
    }e[maxn*5];
    int head[maxn],len;
    void Insert(int x,int y,int dis){
         e[++len].to=y;e[len].dis=dis;e[len].next=head[x],head[x]=len;
    }
    bool vis[maxn];
    long long cnt[maxn],d[maxn];
    bool spfa(int u){
        memset(d,0xf3,sizeof(d));
        queue<int>q;
        q.push(u);
        d[u]=1;
        vis[u]=1;
        cnt[u]=1;
        while(!q.empty()){
            int x=q.front();q.pop();vis[x]=0;
            for(int i=head[x];i;i=e[i].next){
                int v=e[i].to;
                if(d[v]<d[x]+e[i].dis){
                    d[v]=d[x]+e[i].dis;
                    if(!vis[v]){
                        q.push(v);
                        cnt[v]++;
                        vis[v]=1;
                        if(cnt[v]>n){
                            return 1;
                        }
                    }
                }
            }
        }
        return 0;
    }
}G;
void work(){
     n=read(),m=read();
     bool f=0;
     for(int i=1;i<=m;++i){
         int op=read(),x=read(),y=read();
         if(op==1)G.Insert(x,y,0),G.Insert(y,x,0);
         if(op==2){if(x==y)f=1;G.Insert(x,y,1);}
         if(op==3)G.Insert(y,x,0);
         if(op==4){if(x==y)f=1;G.Insert(y,x,1);}
         if(op==5)G.Insert(x,y,0);      
     }
     if(f){
         printf("-1\n");return;
     }    
     for(int i=n;i>0;--i)G.Insert(0,i,0);//玄学优化
     f=G.spfa(0);
     if(f){
         printf("-1\n");return;
     }
     long long ans=0;
     for(int i=1;i<=n;++i){
         ans+=G.d[i];
     }
     printf("%lld\n",ans);
}
int main(){
    work();
    return 0;
}

D 奖学金

先按照成绩排序,枚举每一个数作为中位数,答案为moneyi+前n/2最小值之和+后n/2最小值之和。最小值之和用优先队列维护即可

赛时十分钟打了个线段树,每次枚举重新建树,暴力求最值 60pts

Code

int data[maxn],pos[maxn];
struct Pig{
	long long cs,mo;
}pig[maxn];
bool cmp(Pig x,Pig y){
	return x.cs<y.cs;
}
int n,c,F;
int f[maxn],g[maxn];//f[i] i为中位数前n/2最小值的和, g[i] i为中位数后n/2最小值的和 
void work(){
    priority_queue<long long>q;
	long long sum=0;
    for(int i=1;i<=n/2;++i){
		q.push(pig[i].mo);sum+=pig[i].mo;
	}
	for(int i=n/2+1;i<=c-n/2;++i){
		f[i]=sum;
		if(pig[i].mo<q.top()){sum-=q.top();q.pop();q.push(pig[i].mo);sum+=pig[i].mo;}
	}
	q=priority_queue<long long>();sum=0;
	for(int i=c;i>=c-n/2+1;--i){
		q.push(pig[i].mo);sum+=pig[i].mo;
	}
	for(int i=c-n/2;i>=n/2+1;--i){
		g[i]=sum;
		if(pig[i].mo<q.top()){sum-=q.top();q.pop();q.push(pig[i].mo);sum+=pig[i].mo;}
	}
}
int main(){
	freopen("money.in","r",stdin);
	freopen("money.out","w",stdout);
	n=read(),c=read(),F=read();
	for(int i=1;i<=c;++i){
	    pig[i].cs=read(),pig[i].mo=read();
	}
	sort(pig+1,pig+c+1,cmp);
	long long ans=-1;
	work();
	for(int i=c-n/2;i>=n/2+1;--i){
		if(f[i]+g[i]+pig[i].mo<=F){
			ans=pig[i].cs;break;
		}
	}
	printf("%lld\n",ans);
	return 0;
}
posted @   Chano_sb  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示