新賽道-2024.8 CSP-J組月賽-T3

谦谦2022發表於2024-09-01

題目描述

王老師的班級要開始評選三好學生啦,最後要評選兩個人出來。

王老師班級一共有 n 個學生,編號分別為 1,2,,n,每個人把自己心中的兩名最佳三好學生 a 和 b 告訴 王老師。

  • 可能存在兩個人,他們心中的兩名最佳三好學生是相同的。例如樣例 1 所示。

現在 王老師 要選出兩個人,為了讓學生們滿意,至少需要 m 個人同意最後的決定。所謂同意指的是,某班級學生同意這最終名單,當且僅當該學生心中的兩名最佳三好學生至少有一個出現在最終名單裡。

請你幫 王老師 算算,有多少種可能的組合(與選出來的人的順序無關),符合條件

資料範圍

對於 60% 的資料,n 的範圍 [3,104];

對於 100% 的資料,n 的範圍 [3,105], m 的範圍 [0,n],並且保證 a=b,1a,bn

根據題目可知,我們可以用一個字尾陣列s來維護其間重複的人同意數,則我們可以列舉i,找到最小的答案,則在它後面的所有值便都是答案,最後/2去掉重複條件即可。

程式碼:

#include <bits/stdc++.h>
using namespace std;
#define int long long
int a,b,d[100005],cnt[100005],s[100005],num[100005],vis[100005],n,m,ans;
vector<int>g[100005];

signed main(){
freopen("vote.in","r",stdin);
freopen("vote.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a>>b;
d[a]++,d[b]++;
g[a].push_back(b),g[b].push_back(a);
}
for(int i=1;i<=n;i++)++cnt[d[i]];
for(int i=n;i>=0;i--)s[i]=s[i+1]+cnt[i];
for(int i=1;i<=n;i++){
int de=m-d[i];
if(de<=0)ans+=n-1;
else {
int tmp=s[de];
if(d[i]>=de)tmp--;
for(int j=0;j<g[i].size();j++)num[g[i][j]]=vis[g[i][j]]=0;
for(int j=0;j<g[i].size();j++)num[g[i][j]]++;
for(int j=0;j<g[i].size();j++){
int v=g[i][j];
if(vis[v])continue;
vis[v]=1;
if(d[v]>=de && d[v]-num[v]<de)tmp--;
}
ans+=tmp;
}
}
cout<<ans/2;
return 0;
}
總結:我在寫這題時雖然沒能想出正解,但看出了%60資料O(n^2)能過,於是用了個map來存重複數量,但是在迴圈內map每次新建,浪費了許多空間,需要先判斷是否存在,這的確是我不知道的點,需要加強。

相關文章