返回顶部

高一下二调2

$T1 \qquad $ 排座位
https://tg.hszxoj.com/contest/992/problem/4

$\quad \ \ $ 很难说,开始一眼暴力\(O(n^2)\)(好像不是),再看\(n=1e5\),废了,更不行了。但想起来归并排序,然而并不是归并排序。也是水过样例了,十分……

$T2 \qquad $ 梦中的学校
https://tg.hszxoj.com/contest/992/problem/2
$\quad \ \ $一眼直接变身半糖小子,梦中的梦中……梦中人的梦中,梦不到被吹散,往事如风……空空的天空……
不犯病了(doge)

点击查看图片

$\quad \ \ $算是个DP?记忆化搜索?总之考试的时候没想出来(还爆零了)。

$T3 \qquad $ 激突冲击
https://tg.hszxoj.com/contest/992/problem/3
$\quad \ \ $就是糖果原题,输入输出都没变。

偷一下 zby $tarjan$缩点代码
#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(){
	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;
}
我 $spfa$ 乱卡常过的代码
#include<bits/stdc++.h>
using namespace std;
const int N=150050;
int nx[N<<1],to[N<<1],w[N<<1];
int dis[N],f[N],i,n,m,x,y,k,h[N],t,flag;
long long ans;
inline bool check(int k,int x,int y){
	if((k==2||k==4)&&x==y)return false;
	return true;
}
void add(int x,int y,int z){
	to[++t]=y;
	nx[t]=h[x];
	h[x]=t;
	w[t]=z;
}
int vis[N],q[N<<2],l,r;
inline void spfa(){
    q[++r]=0;
    f[0]=1;
    vis[0]=1;
    while(l<r){
        int x=q[++l];
        f[x]=0;
        for(register int i=h[x];i;i=nx[i]){
            if(dis[to[i]]<dis[x]+w[i]){
                dis[to[i]]=dis[x]+w[i];
                vis[to[i]]++;
                if(vis[to[i]]>=n){
                    flag=1;
                    return ;
                }
                if(!f[to[i]]){
                    q[++r]=to[i];
                    f[to[i]]=1;
                }
            }
        }
    }
    return ;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>n>>m;
	memset(dis,-0x7f,sizeof dis);
	dis[0]=0;
	for(i=1;i<=m;i++){
		cin>>k>>x>>y;
		if(check(k,x,y)){
			if(k==1)add(x,y,0),add(y,x,0);
			else if(k==2)add(x,y,1);
			else if(k==3)add(y,x,0);
			else if(k==4)add(y,x,1);
			else if(k==5)add(x,y,0);
		}else {
			cout<<"-1";
			return 0;
		}
	}
	for(i=n;i>=1;i--)add(0,i,1);
	spfa();
	if(flag)puts("-1");
	else {
		for(i=1;i<=n;i++)ans+=dis[i];
		cout<<ans;
	}
	return 0;
}

$T4 \qquad $ 奖学金
https://tg.hszxoj.com/contest/992/problem/4
$\quad \ \ $本来想打暴力的(虽然最后变成了暴力,T成80了),正解用优先队列预处理一下,再判断就行了。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define intl register int
const int N=1010000;
int n,m,need,su,sum,f[N],g[N],fee;
struct stu{
	int ca,p;
}s[N];
bool cmp(stu x,stu y){return x.ca<y.ca;}
bool cp(stu x,stu y){return x.p<y.p;}
int r(){
	int ans=0;bool f=0;char ch=getchar();
	while(ch<'0' || ch>'9'){if(ch=='-')f=1;ch=getchar();}
	while(ch>='0' && ch<='9'){ans=(ans<<1)+(ans<<3)+(ch^48);ch=getchar();}
	return f?~ans+1:ans;
}
priority_queue<int>q;
signed main(){
	freopen("money.in","r",stdin);
	freopen("money.out","w",stdout);
	n=r();need=r();fee=r();
	for(intl i=1;i<=need;i++)s[i].ca=r(),s[i].p=r();
	sort(s+1,s+1+need,cp);
	int su=0;
	for(intl i=1;i<=n;i++)su+=s[i].p;
	if(su>fee){printf("-1");return 0;}
	
	sort(s+1,s+1+need,cmp);
	int o=n/2;
	for(int i=1;i<=o;i++){
		q.push(s[i].p);
		sum+=s[i].p;
	}
	for(int i=o+1;i<=need-o;i++){
		f[i]=sum;
		if(s[i].p<q.top()){
			sum-=q.top();
			sum+=s[i].p;
			q.pop();
			q.push(s[i].p);
		}
	}
	while(!q.empty())q.pop();
	sum=0;
	for(int i=need;i>=need-o+1;i--){
		q.push(s[i].p);
		sum+=s[i].p;
	}
	for(int i=need-o;i>=o+1;i--){
		g[i]=sum;
		if(s[i].p<q.top()){
			sum-=q.top();
			sum+=s[i].p;
			q.pop();
			q.push(s[i].p);
		}
	}
	for(int i=need-o;i>=o+1;i--){
		if(f[i]+g[i]+s[i].p<=fee){
			printf("%d",s[i].ca);
			return 0;
		}
	}
	return 0;
}

$\quad \ \ $听说有人二分过了,非常不爽(因为我开始也想二分,后来否了,要不然可能不T)。看了看他们代码,发现他们代码满足条件就往右跳,反之往左跳。也是造了个 \(Hack\) 数据,在他们第一次往左跳的点右边设置了一个合法的点(也就是答案)。
$\quad \ \ $ 看着他们被卡的表情也是爽了(doge)

posted @ 2024-04-15 17:15  无敌の暗黑魔王  阅读(30)  评论(2编辑  收藏  举报