【比赛】高一下二调 2

事实证明打水题我还是有一手的

T1 排座位 100Pts

题面

image

算是个签到题。
直接暴力模拟,只要这个数不在自己的位置上就交换一次即可。

赛后题解中有另一种做法:
image

证明的话,数学奥赛的老师也没有具体的办法

抽象,但确实是对的。

代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
typedef long long ll;
int n,a[N],b[N],ans;
int main(){
	freopen("seat.in","r",stdin);
	freopen("seat.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		b[a[i]]=i;
	}
	for(int i=1;i<=n;i++){
		if(a[i]!=i){
			int tmp=a[i];
			swap(a[i],a[b[i]]);
			swap(b[tmp],b[i]);
			ans++;
		}
	}
	cout<<ans;
	return 0;
}

T2 梦中的学校 40Pts

题面

image

记得 \(Huge\) 在第一次考试时说过一句话:

“这题是我们疫情时出的,为了防止你们上网查题解所以改了题面”
“但是你可以查输入输出数据”

所以这题其实是金字塔
赛事看出来是 \(DP\) 了,但一直在想线性 \(DP\) ,遂假;
最后特判样例 \(+\) 两个答案为 \(0\) 的点 \(40\)

题解代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 310, mod = 1e9;
char str[N];
int f[N][N];

int main()
{
    cin >> str + 1;
    int n = strlen(str + 1);
    if(n % 2 == 0)  cout << 0 << endl;
    else
    {
        for (int len = 1; len <= n; len += 2)
            for (int l = 1; l + len - 1 <= n; l ++)
            {
                int r = l + len - 1;
                if(len == 1)    f[l][r] = 1;
                else if(str[l] == str[r])
                {
                    for (int k = l; k < r; k += 2)
                        if(str[k] == str[r])
                            f[l][r] = (f[l][r] + (ll)f[l][k] * f[k + 1][r - 1]) % mod;
                }
            }
        cout << f[1][n] << endl;
    }
    return 0;
}

T3 激突冲击 100Pts

题面

image

其实是糖果

赛时忘了正解怎么打了,也是因为懒得调,用迭代贪心水过了。
我就说我卡你们有用吧,除了 T1 就这题过的多

正解
#include<bits/stdc++.h>
#include<vector>
using namespace std;
typedef long long ll;
const int N=1e6+5;
int n,m,op,x,y;
int dfn[N],low[N],num,cnt,size[N],id[N];
int f[N],in[N];
ll ans;
struct node{
	int next,w;
};
vector<node> e1[N],e2[N];
bool vis[N];
stack<int> s;
inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
void tarjan(int x){
	dfn[x]=low[x]=++num;
	vis[x]=1;
	s.push(x);
	for(auto &i:e1[x]){
		int nx=i.next;
		if(!dfn[nx]){
			tarjan(nx);
			low[x]=min(low[x],low[nx]);
		}
		else if(vis[nx]==1){
			low[x]=min(low[x],dfn[nx]);
		}
	}
	if(dfn[x]==low[x]){
		int y;
		cnt++;
		do{
			y=s.top();
			s.pop();
			id[y]=cnt;
			size[cnt]++;
			vis[y]=0;
		}while(x!=y);
	}
}
int main(){
	freopen("bomb.in","r",stdin);
	freopen("bomb.out","w",stdout);
	n=read();m=read();
	for(int i=1;i<=m;i++){
		op=read();x=read();y=read();
		switch(op){
			case 1:
				e1[x].push_back({y,0});
				e1[y].push_back({x,0});
				break;
			case 2:
				e1[x].push_back({y,1});
				break;
			case 3:
				e1[y].push_back({x,0});
				break;
			case 4:
				e1[y].push_back({x,1});
				break;
			default:
				e1[x].push_back({y,0});
		}
	}
	for(int i=1;i<=n;i++){
		if(!dfn[i])tarjan(i);
	}
	for(int i=1;i<=n;i++){
		for(auto &j:e1[i]){
			int nx=j.next;
			x=id[i],y=id[nx];
			if(x==y&&j.w==1){
				cout<<-1;
				return 0;
			}
			if(x!=y){
				e2[x].push_back({y,j.w});
				in[y]++;
			}
		}
	}
	queue<int> q;
	for(int i=1;i<=cnt;i++){
		if(!in[i]){
			q.push(i);
			f[i]=1;
		}
	}
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(auto &i:e2[u]){
			int nx=i.next;
			in[nx]--;
			f[nx]=max(f[nx],f[u]+i.w);
			if(!in[nx])q.push(nx);
		}
	}
	for(int i=1;i<=cnt;i++){
		ans+=(ll)f[i]*size[i];
	}
	cout<<ans;
	return 0;
}
迭代贪心法
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
struct order{
	int t,a,b;
}e[N];
int n,m,c4[N];
int main(){
	freopen("bomb.in","r",stdin);
	freopen("bomb.out","w",stdout);
	n=read();m=read();
	for(int i=1;i<=m;i++){
		e[i].t=read();e[i].a=read();e[i].b=read();
	}
	for(int i=1;i<=n;i++)c4[i]=1;
	for(register int T=1;T<=1000;T++){
		for(register int i=1;i<=m;i++){
			if(e[i].t==1)c4[e[i].a]=c4[e[i].b]=max(c4[e[i].a],c4[e[i].b]);
			else if(e[i].t==2)c4[e[i].b]=max(c4[e[i].b],c4[e[i].a]+1);
			else if(e[i].t==3)c4[e[i].a]=max(c4[e[i].a],c4[e[i].b]);
			else if(e[i].t==4)c4[e[i].a]=max(c4[e[i].a],c4[e[i].b]+1);
			else c4[e[i].b]=max(c4[e[i].b],c4[e[i].a]);
		}	
	}
	for(register int i=1;i<=m;i++){
		if(e[i].t==1){
			if(c4[e[i].a]!=c4[e[i].b]){
				cout<<-1;
				return 0;
			}
		}
		else if(e[i].t==2){
			if(c4[e[i].a]>=c4[e[i].b]){
				cout<<-1;
				return 0;
			}
		}
		else if(e[i].t==3){
			if(c4[e[i].a]<c4[e[i].b]){
				cout<<-1;
				return 0;
			}
		}
		else if(e[i].t==4){
			if(c4[e[i].a]<=c4[e[i].b]){
				cout<<-1;
				return 0;
			}
		}
		else{
			if(c4[e[i].a]>c4[e[i].b]){
				cout<<-1;
				return 0;
			}
		}
	}
	ll ans=0;
	for(int i=1;i<=n;i++){
		ans+=c4[i];
	}
	cout<<ans;
	return 0;
}

T4 奖学金 70Pts

题面

image

原题:洛谷 P3963

思路清晰:从大到小枚举中位数,左右两边贪心找最小值,可行就直接 \(break\) 掉输出答案。
思路是清晰的,但三个 sort 毁了我的 AC 梦
算复杂度的时候只找了循环节,没看着 \(sort\) ,挂了 \(30\)
正解不需要 \(sort\) ,开优先队列扫即可,因为每次只有一个点出队和入队。

TLEのsort
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
typedef long long ll;
struct pig{
	ll score,money;
}a[N];
bool cmp1(pig a,pig b){
	return a.score<b.score;
}
bool cmp2(pig a,pig b){
	return a.money<b.money;
}
ll n,c,f;
int main(){
	freopen("money.in","r",stdin);
	freopen("money.out","w",stdout);
	cin>>n>>c>>f;
	for(int i=1;i<=c;i++){
		scanf("%lld%lld",&a[i].score,&a[i].money);
	}
	ll sum=0;
	sort(a+1,a+1+c,cmp2);
	for(int i=1;i<=n;i++)sum+=a[i].money;
	if(sum>f){
		cout<<-1;
		return 0;
	}
	int mid=(n+1)>>1,side=(n-1)>>1;
	for(int i=c-mid+1;i>=mid;i--){
		sort(a+1,a+1+c,cmp1);
		int ans=a[i].score;
		sort(a+1,a+i,cmp2);sort(a+i+2,a+1+c,cmp2);
		sum=0;
		for(int j=1;j<=side;j++){
			sum+=a[j].money;
		}
		for(int j=i+1;j<=i+side;j++){
			sum+=a[j].money;
		}
		sum+=a[i].money;
		if(sum<=f){
			cout<<ans;
			return 0;
		}
	}
	return 0;
}
优先队列(代码来自GGR)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define ps push_back
#define mk make_pair
#define fi first
#define se second
const int N=1e5+10;
struct jj{
	int cj,w,id;
	bool operator <(const jj&x){
		return cj<x.cj;
	}
}bi[N];
int a[N],n,c,ans;
ll f;
bool v[N];
priority_queue<pii >q2;
priority_queue<int> q1;
int main(){
	freopen("money.in","r",stdin);
	freopen("money.out","w",stdout);
	cin>>n>>c>>f;
	int k=n/2;
	for(int i=1;i<=c;i++){
		scanf("%d%d",&bi[i].cj,&bi[i].w);
	}
	sort(bi+1,bi+1+c);
	ll l=0,r=0;
	for(int i=1;i<=c;i++)bi[i].id=i;
	for(int i=1;i<=k;i++){
		q1.push(bi[i].w);
		l+=bi[i].w;
	}
	for(int i=k+1;i<=c;i++){
		q2.push(mk(-bi[i].w,bi[i].id));
	}
	for(int i=1;i<=k;i++){
		r-=q2.top().fi;v[q2.top().se]=1;q2.pop();
	}
	for(int i=k+1;i<=c-k;i++){
		if(i!=k+1&&bi[i-1].w<q1.top()){
			l-=q1.top();l+=bi[i-1].w;
			q1.pop();q1.push(bi[i-1].w);
		}
		while(!q2.empty()&&q2.top().se<=i)q2.pop();
		if(v[i]){
			r-=bi[i].w;r-=q2.top().fi;v[i]=0;v[q2.top().se]=1;q2.pop();
		}
		if(r+l+bi[i].w<=f){
			ans=max(ans,bi[i].cj);
		}
	}
	if(!ans){
		cout<<-1;
		return 0;
	}
	cout<<ans<<endl;
}

其实好像也可以用二分做,但我感觉没有单调性,于是赛时没打。

update:确实没单调性,被 Hack 掉了。

二分(代码来自教授)
#include<bits/stdc++.h>
using namespace std;
struct node1
{
	long long mny,soe;
	bool operator<(const node1 &A)const
	{
		if(mny==A.mny)
		{
			return soe>A.soe;
		}
		return mny<A.mny;
	}
}pig1[200002];
struct node2
{
	long long mny,soe;
	bool operator<(const node2 &A)const
	{
		if(soe==A.soe)
		{
			return mny<A.mny;
		}
		return soe<A.soe;
	}
}pig2[200002];
long long a,b,c;
inline bool check(long long x)
{
	if(x<=a/2||x>b-a/2)
	{
		return false;
	}
	long long num1=0,num2=0,sm=0;
	bool deng=false;
	for(register long long i=1;i<=b;i++)
	{
		if(pig1[i].soe==pig2[x].soe&&deng==false)
		{
			sm+=pig1[i].mny;
			if(sm>c)
			{
				return false;
			}
			deng=false;
			continue;
		}
		if(pig1[i].soe<=pig2[x].soe&&num1<a/2)
		{
			num1++;
			sm+=pig1[i].mny;
			if(sm>c)
			{
				return false;
			}
			continue;
		}
		if(pig1[i].soe>=pig2[x].soe&&num2<a/2)
		{
			num2++;
			sm+=pig1[i].mny;
			if(sm>c)
			{
				return false;
			}
			continue;
		}
	}
	return true;
}
int main()
{
	freopen("money.in","r",stdin);
	freopen("money.out","w",stdout);
	scanf("%lld%lld%lld",&a,&b,&c);
	for(register long long i=1;i<=b;i++)
	{
		scanf("%lld%lld",&pig1[i].soe,&pig1[i].mny);
		pig2[i].soe=pig1[i].soe;
		pig2[i].mny=pig1[i].mny;
	}
	sort(pig1+1,pig1+1+b);
	sort(pig2+1,pig2+1+b);
	long long m=1,n=b;
	while(n-m>1)
	{
		long long l=(m+n)>>1;
		if(check(l)==true)
		{
			m=l;
		}
		else
		{
			n=l;
		}
	}
	if(check(n)==true)
	{
		printf("%lld",pig2[n].soe);
		fclose(stdin);
		fclose(stdout);
		return 0;
	}
	if(check(m)==true)
	{
		printf("%lld",pig2[m].soe);
		fclose(stdin);
		fclose(stdout);
		return 0;
	}
	puts("-1");
	return 0;
}

后记

感谢 @GGR 送来的 rk1 。
GGR T1 把 ios::sync_with_stdio(false);fclose(stdin);fclose(stdout); 混用导致爆零了
T3 犯唐没开 long long 挂了 \(9\) 分;
都对他就 AK 了,感觉挺可惜的。

$\ $

这次出现了少见的 freopen 出错事件。
包括但不限于:
freopen("money.out","r",stdout);
freopen("bomb,out","w",stdout);
freopen("r", "bomb.in", stdin);
frepoen("school.in", "r", stdin);

$\ $

最后用 \(\text{Huge}\) 的一句话来结尾吧:

“难吗?这次考试和上次一样简单。”

posted @ 2024-04-15 15:33  萝卜甜了  阅读(32)  评论(0编辑  收藏  举报