[39] (多校聯訓) A層衝刺NOIP2024模擬賽01

HaneDaniko發表於2024-10-03

你們不感覺最近機房網越來越慢了嗎,現在下個 10M 的東西要用三分鐘,而且期間訪問不了網站

整個機房分 1000Mbps 的頻寬為啥只能分這麼一點, huge 拿我電腦挖礦了?

本來以為多校就是多校的,結果是真的多校,一百一十多個人在一塊考

huge: 參加的都是咱們北方這幾個強校

你說得對,但是廣東為啥是北方

A.構造字串

維護並查集,同一個連通塊內的數字應該相同

對於一個要求 \((x_i,y_i,z_i)\),應該讓 \(\forall j\in[0,z_i-1]\),連線 \(x_i+j,y_i+j\),這樣才能保證在規定範圍內的數字都相等

其次來看不合法的,不合法的就是一定不能相等的,顯然應該是每組詢問中的 \(x_i+z_i\)\(y_i+z_i\),因為如果他倆相等的話,答案就不是 \(z_i\) 了,而是 \(z_i+1\)

那麼我們可以貪心地做這道題,每次遇到沒填的數就考慮填入最小的數,然後把相同連通塊內的數都填成一樣的數

需要注意你填的時候需要保證能夠滿足所有的限制條件,比如現在有三個數,\(1\)\(3\) 相同,\(2\)\(3\) 不同,那麼你給 \(1,3\) 填了 \(0\),給 \(2\) 填的時候需要注意一下滿足所有的限制條件,賽時沒判斷後方的限制條件,所以這裡填的是 \(0\),再往後挪一位就錯了

#include<bits/stdc++.h>
using namespace std;
int n,m,cnt;
struct ques{
    int x,y;
}q[1001];
int a[1001];
struct dsu{
    int fa[1001];
    void clear(int n){
        for(int i=1;i<=n;++i){
            fa[i]=i;
        }
    }
    int find(int id){
        if(id==fa[id]) return id;
        return fa[id]=find(fa[id]);
    }
    void join(int x,int y){
        int fx=find(x),fy=find(y);
        if(fx!=fy){
            fa[max(fx,fy)]=min(fx,fy);
        }
    }
    inline int operator [](int id){
        return find(id);
    }
}d;
bool vis[1001],ban[1001][1001];
int main(){
	freopen("str.in","r",stdin);
	freopen("str.out","w",stdout);
	scanf("%d %d",&n,&m);
	d.clear(n);
    while(m--){
		int x,y,z;
        scanf("%d %d %d",&x,&y,&z);
		for(int i=1;i<=z;++i){
			d.join(x+i-1,y+i-1);
		}
		if(x+z!=n+1 or y+z!=n+1){
		    q[++cnt]={x+z,y+z};
        }
	}
	for(int i=1;i<=n;++i){
        if(vis[d[i]]){
            continue;
        }
        vis[d[i]]=1;
		for(int j=0;j<=n;++j){
            if(!ban[d[i]][j]){
                a[d[i]]=j;
                break;
            }
        }
		for(int j=1;j<=cnt;++j){
			int f1=d[q[j].x],f2=d[q[j].y];
			if(f1==f2){
                cout<<-1<<"\n";
                return 0;
            }
			if(min(f1,f2)==d[i]){
                ban[max(f1,f2)][a[min(f1,f2)]]=true;
            }
		}
		for(int j=i+1;j<=n;++j){
			if(d[j]==d[i]){
                a[j]=a[d[i]];
            }
		}
	}
	for(int i=1;i<=n;++i){
        cout<<a[i]<<" ";
    }
    cout<<"\n";
}

B.尋寶

本場最送

連通性問題,注意到 \(k\) 很小,顯然可以縮點,把所有聯通的節點都連在一起(忽略傳送門)

然後處理傳送門,相當於在連通塊之間聯有向邊

判斷聯通的時候直接跑 DFS 即可,由於邊很少,單次查詢最高只有 \(O(k)\)

發現只給了 \(n\times m\) 的範圍,靜態陣列開不下,所以題解說用 bitset 存,啥年代了還在用 bitset,vector 擴容不是更好

#include<bits/stdc++.h>
using namespace std;
int n,m,k,q;
vector<vector<int>>mp;
struct door{
	int x1,x2,y1,y2;
}de[101];
int cnt=0;
struct node{
	int x,y;
};
queue<node>p;
bool vis[50001];
void bfs(int x,int y,int loc){
	while(!p.empty()) p.pop();
	p.push({x,y});
	while(!p.empty()){
		node u=p.front();p.pop();
		if(mp[u.x][u.y]!=0) continue;
		mp[u.x][u.y]=loc;
		if(u.x<n) p.push({u.x+1,u.y});
		if(u.x>1) p.push({u.x-1,u.y});
		if(u.y<m) p.push({u.x,u.y+1});
		if(u.y>1) p.push({u.x,u.y-1});
	}
}
vector<int>e[50001];
bool judge(int x,int tar){
	if(x==tar) return true;
	vis[x]=true;
	for(int i:e[x]){
		if(!vis[i] and judge(i,tar)) return true;
	}
	return false;
}
int main(){
//	freopen("treasure/treasure4.in","r",stdin);
//	freopen("out.out","w",stdout);
	freopen("treasure.in","r",stdin);
	freopen("treasure.out","w",stdout);
	scanf("%d %d %d %d",&n,&m,&k,&q);
	mp.resize(n+1);
	for(int i=1;i<=n;++i){
		mp[i].resize(m+1);
	}
	for(int i=1;i<=n;++i){
		string s;
		cin>>s;
		for(int j=0;j<=m-1;++j){
			mp[i][j+1]=(s[j]=='.'?0:-1);
		}
	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j){
			if(mp[i][j]==0){
				bfs(i,j,++cnt);
			}
		}
	}
//	for(int i=1;i<=n;++i){
//		for(int j=1;j<=m;++j){
//			cout<<mp[i][j]<<" ";
//		}
//		cout<<endl;
//	}
	for(int i=1;i<=k;++i){
		scanf("%d %d %d %d",&de[i].x1,&de[i].y1,&de[i].x2,&de[i].y2);
		if(mp[de[i].x1][de[i].y1]!=mp[de[i].x2][de[i].y2]){
			e[mp[de[i].x1][de[i].y1]].push_back(mp[de[i].x2][de[i].y2]);
		}
	}
	while(q--){
		int a,b,c,d;
		scanf("%d %d %d %d",&a,&b,&c,&d);
		for(int i=1;i<=cnt;++i) vis[i]&=0;
		putchar(judge(mp[a][b],mp[c][d])+'0');putchar('\n');
	}
}
/*
4 4 2 1
.#..
##..
#...
...#
1 1 1 3
4 1 4 2
4 1 3 2
*/

C.序列

\(n^2\)

設計 \(f_i\) 表示從 \(i\) 開始的子序列最大值

對每次詢問轉移,轉移方程

\[f_i=\begin{cases}\max(a-kb,f_{i+1}+a-kb)\qquad i\ge p_i\\f_{i+1}+a-kb\qquad \text{otherwise}\end{cases} \]

從後向前轉移,統計答案從 \([1,p_i]\) 取最大值

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
struct yuanshen{
	int a,b;
}y[1000001];
int f[1000002];
signed main(){
//	freopen("seq/seq3.in","r",stdin);
//	freopen("out.out","w",stdout);
	freopen("seq.in","r",stdin);
	freopen("seq.out","w",stdout);
	scanf("%lld %lld",&n,&m);
	for(int i=1;i<=n;++i){
		scanf("%lld %lld",&y[i].a,&y[i].b);
	}
	while(m--){
		int p,k;scanf("%lld %lld",&p,&k);
		for(int i=1;i<=n;++i) f[i]&=0;
		for(int i=n;i>=p;--i){
			f[i]=max({y[i].a-k*y[i].b,f[i+1]+y[i].a-k*y[i].b});
		}
		int ans=f[p];
		for(int i=p-1;i>=1;--i){
			f[i]=f[i+1]+y[i].a-k*y[i].b;
			ans=max(f[i],ans);
		}
		cout<<ans<<'\n';
	}
}

E.我要掛一道題

掛一道題

做之前:若智,這有啥意義

做之後:若智


若智,誰放的
我最愛去的唱片店    //在看到這句話之前 我一直以為是 我最愛吃的炒麵片
昨天是她的最後一天
曾經讓我陶醉的碎片
全都散落在街邊
我最愛去的書店    //我最愛吃的薯片
她也沒撐過這個夏天   //碼的還以為這是啥美食歌
回憶文字流淌著懷念
可是已沒什麼好懷念
可是你曾經的那些夢
都已變得模糊看不見
那些為了理想的戰鬥
也不過為了錢
可是我最恨的那個人
他始終沒死在我面前   //迷惑句子
還沒年輕就變得蒼老
這一生無解
沒有我的空間
沒有我的空間
沒有我的空間
沒有我的空間
你曾熱愛的那個人
這一生也不會再見面
你等在這文化的廢墟上
已沒人覺得你狂野
那些讓人敬仰的神殿
只在無知的人心中靈驗
我住在屬於我的豬圈      //?
這一夜無眠
我不要在失敗孤獨中死去
我不要一直活在地下里
物質的騙局    //有這句?
匆匆的螞蟻
沒有文化的人不傷心
我不要在失敗孤獨中死去
我不要一直活在地下里
物質的騙局
匆匆的螞蟻
沒有文化的人不傷心
他不傷心
我最愛去的唱片店
昨天是她的最後一天
曾經讓我陶醉的碎片
全都散落在街邊
我最愛去的書店
她也沒撐過這個夏天
回憶文字流淌著懷念
已不能懷念
我不要在失敗孤獨中死去
我不要一直活在地下里
物質的騙局
匆匆的螞蟻
沒有文化的人不傷心
我不要在失敗孤獨中死去
我不要一直活在地下里
物質的騙局
匆匆的螞蟻
沒有文化的人不傷心
他不傷心
我不要在失敗孤獨中死去
我不要一直活在地下里
物質的騙局
匆匆的螞蟻
沒有文化的人不傷心
我不要在失敗孤獨中死去
我不要一直活在地下里
物質的騙局
匆匆的螞蟻
沒有文化的人不傷心
他不會傷心
他也會傷心
傷心

相關文章