反省一下自己最近的狀況。
發現自己寫yy題和dp題的水平有所下降(本來就沒多高還掉,跟我昨天剛掉的CFrank一樣),最近幾天的比賽和寫題目都非常不順心。這幾天儘量突破逆境吧。
Description
大帝擁有n個星球,因爲距離非常遙遠,所以大帝在他所居住的1號星球和他的軍事基地霸中所在的2號星球建造了兩個傳送門,這樣從1號星球到2號星球就只需要250分鐘,回去也一樣(雙向)。
由於科技的發展,各個星球陸陸續續建造了和自己居民最經常去的星球之間的傳送門,並且他們的傳送門只需要1個小時(真快啊!),他們發現和別的星球建設傳送門對促進經濟發展有很大的幫助,於是向和其他所有星球建設傳送門發展。
大帝突然發現兩兩星球的傳送門的建設會威脅到他的安全,可是他又想促進自己帝國的發展,於是他請到了他精心培養的你,希望你能幫他解決這個難題。
Input
- 第一行爲兩個由空格隔開的整數
n(2≤n≤4∗104) 和m(0≤m≤106) ,n 表示星球數,m 表示其他星球已經建造的傳送門的對數(傳送門都是兩兩建造的,但不包括大帝在1號和2號的)。- 接下來
m 行每行兩個由空格隔開的整數x,y (2≤x,y≤4∗104) ,表示這兩個星球建造了傳送門連接。Sample Input
10 10
1 3
3 5
5 7
7 9
2 9
1 4
4 6
6 8
8 10
2 10Input Details
實線連接的是已經造好傳送門的兩星球,虛線連接表示可以增加建造的傳送門兩星球。
可以看出,建造了10對以後,從1號到2號星球還是大帝的1->2傳送門最快。
Output
- 一個整數,表示還能讓多少對傳送門建造,但又不會比大帝從1號星球到2號星球快(就是說增加傳送門後,從1號星球到2號星球還是大帝的傳送門最快)。
Sample Output
10
思路轉自Spy大神。
首先我們可以將原圖作如下等效的變形:
每一層都代表着該點最短到1和2的距離。有以下結論:
- 顯然除了1,2外,其他點都會被分進這4層裏。那麼與1相連的,到1的最短距離爲2的點只能放在1,2層;與2相連的,到2的最短距離爲2的點只能放在4,3層。
- 對於在某一層的點,它只能和本層與相鄰層的點連線,如果跨過一層連線,就會導致1,2的最短距離不是5了。
其他剩餘沒有被扔進圖裏的點,將其視作第2,3層中某層的點。這樣首先是不會違背題意的,而且也更優:
- 如果扔進第1層,那麼其增加的邊個數是
size1+1+size2 。 - 如果扔進第2層,那麼其增加的邊個數是
size1+size2+size3 。
顯然
size3≥1 ,所以扔進中間兩層更優。- 如果扔進第1層,那麼其增加的邊個數是
- 顯然增加的數值只會跟每層實際存在的點的個數有關,故可以枚舉有多少點進入2層,多少點進入3層,再計算即可。
基本轉自Spy大神)
#include <bits/stdc++.h>
#define M 40005
using namespace std;
typedef long long ll;
inline void Rd(int &res){
res=0;char c;
while(c=getchar(),c<48);
do res=(res<<3)+(res<<1)+(c^48);
while(c=getchar(),c>47);
}
vector<int>G[M];
int id[M],cnt[6],rcnt[6];
int main(){
int n,m;Rd(n),Rd(m);
for(int i=1;i<=m;i++){
int u,v;
Rd(u),Rd(v);
G[u].push_back(v);
G[v].push_back(u);
}
memset(id,-1,sizeof(id));
id[1]=0,id[2]=5;
for(int j=0;j<G[1].size();j++){
int v=G[1][j];
id[v]=1,cnt[id[v]]++;
}
for(int j=0;j<G[2].size();j++){
int v=G[2][j];
id[v]=4;cnt[id[v]]++;
}
for(int i=1;i<=n;i++)
if(id[i]==1){
for(int j=0;j<G[i].size();j++){
int v=G[i][j];
if(!id[v]){
id[v]=2;
cnt[id[v]]++;
}
}
}else if(id[i]==4){
for(int j=0;j<G[i].size();j++){
int v=G[i][j];
if(!id[v]){
id[v]=3;
cnt[id[v]]++;
}
}
}
int Cnt=0;
for(int i=1;i<=n;i++)Cnt+=(id[i]==-1);//沒有分配到層的元素個數
// printf("Cnt=%d\n",Cnt);
rcnt[1]=cnt[1],rcnt[4]=cnt[4];
int ans=0,res=rcnt[1]*(rcnt[1]-1)/2+rcnt[4]*(rcnt[4]-1)/2+1*rcnt[1]+rcnt[4]*1;
for(int k=0;k<=Cnt;k++){
rcnt[2]=cnt[2]+k,rcnt[3]=cnt[3]+Cnt-k;
int tmp=rcnt[2]*(rcnt[2]-1)/2+rcnt[3]*(rcnt[3]-1)/2+
rcnt[1]*rcnt[2]+rcnt[2]*rcnt[3]+rcnt[3]*rcnt[4];
ans=max(tmp,ans);
}
cout<<ans+res-m<<endl;
}