赛后补题:
A:(https://codeforces.com/contest/449/problem/B)
最短路+思维
对不起,我不会写Dijkstra
不知道从什么时候开始,我的Dij一直是这样的:
1 struct cmp{ 2 bool operator()(int a,int b){ 3 return dis[a]>dis[b]; 4 } 5 }; 6 priority_queue<int,vector<int>,cmp>pq;
正确写法:
struct cmp { bool operator()(pil a, pil b) { return a.second > b.second; }; }; priority_queue<pil, vector<pil >, cmp> pq;
很明显这是错的。。。hhhhh
原因在于:这个堆因为dis[u]会变化,所以这个堆根本就是个假的堆!
从另一个角度来讲:
队列中维护的是入队时候的dis而不是时时变化的dis,dis会随着更新而变化
还有一个地方:
1 void dij() { 2 fill(dis, dis + maxn, 1e18); 3 priority_queue<pil, vector<pil >, cmp> pq; 4 pq.push({1, 0}); 5 dis[1] = 0; 6 while (!pq.empty()) { 7 int now = pq.top().first; 8 pq.pop(); 9 if (vis[now]) continue; //一定要有入队标记,否则重复入队会T到飞起 10 vis[now] = 1; 11 for (int i = 0; i < G[now].size(); ++i) { 12 int to = G[now][i].first, 13 v = G[now][i].second; 14 15 if (!vis[to] && dis[to] > dis[now] + v) { //这里更新的时候也要看是否已经入队 16 ind[to] = 1; 17 dis[to] = dis[now] + v; 18 pq.push({to, dis[to]}); 19 } //else if (dis[to] == dis[now] + v) ++ind[to]; //这是根据本题题意来的。 20 } 21 } 22 }
综上所述:我不会写dij,,,,hhhhh(天知道我之前的最短路都是怎么过的)
下面贴完整代码:
1 #include <bits/stdc++.h> 2 #define ll long long 3 #define pil pair<int,ll> 4 using namespace std; 5 6 const int maxn=1e5+5; 7 bool vis[maxn]; 8 int n,m,k,ind[maxn]; 9 ll dis[maxn],minn[maxn]; 10 vector<pil>G[maxn]; 11 12 13 struct cmp { 14 bool operator()(pil a, pil b) { 15 return a.second > b.second; 16 }; 17 }; 18 19 20 void dij() { 21 fill(dis, dis + maxn, 1e18); 22 priority_queue<pil, vector<pil >, cmp> pq; 23 pq.push({1, 0}); 24 dis[1] = 0; 25 while (!pq.empty()) { 26 int now = pq.top().first; 27 pq.pop(); 28 if (vis[now]) continue; 29 vis[now] = 1; 30 for (int i = 0; i < G[now].size(); ++i) { 31 int to = G[now][i].first, 32 v = G[now][i].second; 33 34 if (!vis[to] && dis[to] > dis[now] + v) { 35 ind[to] = 1; 36 dis[to] = dis[now] + v; 37 pq.push({to, dis[to]}); 38 } else if (dis[to] == dis[now] + v) ++ind[to]; 39 } 40 } 41 } 42 43 int main() { 44 ios::sync_with_stdio(0); 45 cin >> n >> m >> k; 46 for (int i = 1; i <= m; ++i) { 47 int a, b, c; 48 cin >> a >> b >> c; 49 G[a].push_back({b, c}); 50 G[b].push_back({a, c}); 51 } 52 int ans = 0; 53 for (int i = 1; i <= k; ++i) { 54 int a; 55 ll b; 56 cin >> a >> b; 57 if (minn[a]) { 58 ++ans; 59 minn[a] = min(minn[a], b); 60 } else minn[a] = b; 61 } 62 for (int i = 2; i <= n; ++i) { 63 if (minn[i]) { 64 G[1].push_back({i, minn[i]}); 65 G[i].push_back({1, minn[i]}); 66 } 67 } 68 dij(); 69 for (int i = 2; i <= n; ++i) { 70 if (minn[i]) { 71 if (minn[i] > dis[i]) { 72 ++ans; 73 } 74 if (minn[i] == dis[i] && ind[i] > 1)++ans; 75 } 76 } 77 cout << ans << endl; 78 }
还要注意的是:最短路图的入度是在Dij的过程中确定的,更新一次后(dis[to]>dis[now]+v),to的入度变为1,如果(dis[to]==dis[now]+v),to的入度+1
确定入度和最短路计数也不太一样,计数时,更新一次后(dis[to]>dis[now]+v),to的入度变为indegree[now],如果(dis[to]==dis[now]+v),indegree[to]+indegree[now]
B - Phillip and Trains
BFS/DFS水题,注意一下人的运动要先前进一格在上下移动,不可以先上下移动再前进一格,开始没读好题
1 #include<bits/stdc++.h> 2 #define pii pair<int,int> 3 using namespace std; 4 int start; 5 6 const int maxn=1e3+5; 7 char plat[5][maxn]; 8 bool vis[5][maxn]; 9 int n; 10 int all_f; 11 bool move(int x,int y) 12 { 13 return plat[x][y+1]=='.' && plat[x][y+2]=='.'; 14 } 15 bool bfs() 16 { 17 queue<pii>q; 18 q.push({start,1}); 19 while(!q.empty()) 20 { 21 pii now=q.front(); 22 q.pop(); 23 int x=now.first,y=now.second; 24 if(y>=n) return 1; 25 if(vis[x][y]) continue; 26 vis[x][y]=1; 27 if(plat[x][y+1]!='.') continue; 28 for(int i=-1;i<=1;++i) 29 { 30 if(plat[x+i][y+1]=='.' && move(x+i,y+1)) 31 { 32 q.push({x+i,y+3}); 33 } 34 } 35 } 36 return 0; 37 } 38 int main() 39 { 40 int t; 41 ios::sync_with_stdio(0); 42 cin>>t; 43 while(t--) 44 { 45 all_f=0; 46 memset(plat,0,sizeof(plat)); 47 memset(vis,0,sizeof(vis));int no; 48 cin>>n>>no; 49 cin>>plat[1]+1>>plat[2]+1>>plat[3]+1; 50 for(int i=1;i<=3;++i) 51 { 52 for(int j=1;j<=n;++j) 53 { 54 if(plat[i][j]=='s') start=i; 55 plat[i][j+n]='.'; 56 } 57 } 58 cout<<(bfs()?"YES":"NO")<<endl; 59 } 60 }
C - A Mist of Florescence
给4个数abcd表示ABCD四个字母连通块的个数,构造一个矩阵使其ABCD连通块的个数为abcd
构造+思维,
排序以下,由小到大分别为ABCD,ABC各拿出来一个,先ABABAB排,用C个开一层,再用B隔开一层,再CDCDCD排,A隔开然后BDBDBD排,最后剩下的B/D嵌到A中。
1 #include<bits/stdc++.h> 2 #define pii pair<int,int> 3 using namespace std; 4 int a,b,c,d; 5 int ans[51][51]; 6 pii blo[10]; 7 int main() 8 { 9 for(int i=1;i<=4;++i) cin>>blo[i].first,blo[i].second=i; 10 sort(blo+1,blo+1+4); 11 a=blo[1].first,b=blo[2].first,c=blo[3].first,d=blo[4].first; 12 --a,--b,--c; 13 int minn=a; 14 int col=1,row=1; 15 b-=a; 16 while(a) 17 { 18 if(row&1) 19 { 20 ans[row][col++]=1; 21 ans[row][col++]=2; 22 } 23 else 24 { 25 ans[row][col++]=2; 26 ans[row][col++]=1; 27 } 28 --a; 29 if(col==51) 30 { 31 col=1; 32 ++row; 33 } 34 } 35 for(int i=col;i<=50;++i) ans[row][i]=3; 36 for(int i=1;i<=50;++i) ans[row+1][i]=3; 37 for(int i=1;i<=50;++i) ans[row+2][i]=2; 38 minn=c; 39 row+=3,col=1; 40 d-=c; 41 while(c) 42 { 43 if(row&1) 44 { 45 ans[row][col++]=3; 46 ans[row][col++]=4; 47 } 48 else 49 { 50 ans[row][col++]=4; 51 ans[row][col++]=3; 52 } 53 --c; 54 if(col==51) 55 { 56 col=1; 57 ++row; 58 } 59 } 60 61 for(int i=col;i<=50;++i) ans[row][i]=1; 62 for(int i=1;i<=50;++i) ans[row+1][i]=1; 63 row+=2;col=1; 64 minn=min(b,d); 65 int bb=b,dd=d; 66 while(minn) 67 { 68 //cout<<"Q"<<endl; 69 if(row&1) 70 { 71 ans[row][col++]=2; 72 ans[row][col++]=4; 73 } 74 else 75 { 76 ans[row][col++]=4; 77 ans[row][col++]=2; 78 } 79 --minn; 80 if(col==49) 81 { 82 col=1; 83 ans[row][49]=1; 84 ans[row][50]=1; 85 ++row; 86 } 87 } 88 for(int i=col;i<=50;++i) ans[row][i]=1; 89 ++row; 90 for(int i=1;i<=50;++i) ans[row][i]=1; 91 ++row; 92 int red=abs(b-d); 93 col=1; 94 while(red) 95 { 96 --red; 97 ans[row][col++]=7; 98 ans[row][col++]=1; 99 if(col==51) 100 { 101 col=1,++row; 102 for(int i=1;i<=50;++i) ans[row][i]=1; 103 ++row; 104 } 105 } 106 for(int i=col;i<=50;++i) ans[row][i]=1; 107 int p=bb>dd?2:4; 108 for(int i=1;i<=50;++i) 109 { 110 for(int j=1;j<=50;++j) 111 { 112 if(ans[i][j]==7) ans[i][j]=p; 113 } 114 } 115 cout<<row<<" "<<50<<endl; 116 for(int i=1;i<=row;++i) 117 { 118 for(int j=1;j<=50;++j) 119 { 120 //cout<<ans[i][j]; 121 printf("%c",'A'-1+blo[ans[i][j]].second); 122 } 123 puts(""); 124 } 125 cout<<endl; 126 }
D - Unbearable Controversy of Being
给一个有向图,问图中有多少个图示单元。
思维+遍历图+水题
对于每个起始点,找到深度所有为2的点,每个点出现次数计数一下,复杂度O(n^2),答案为每个数的C(cnt,2)求和。
1 #include<bits/stdc++.h> 2 long long ans=0; 3 using namespace std; 4 const int maxn=4000; 5 inline int cnt(int n){return n*(n-1)/2;} 6 int n,m,vis[maxn]; 7 vector<int>G[maxn]; 8 void dfs(int now,int dep) 9 { 10 if(dep==2) 11 { 12 ++vis[now]; 13 return; 14 } 15 for(int i=0;i<G[now].size();++i) 16 { 17 int to=G[now][i]; 18 dfs(to,dep+1); 19 } 20 } 21 int main() 22 { 23 ios::sync_with_stdio(0); 24 cin>>n>>m; 25 for(int i=1;i<=m;++i) 26 { 27 int a,b;cin>>a>>b; 28 G[a].push_back(b); 29 } 30 31 for(int i=1;i<=n;++i) 32 { 33 memset(vis,0,sizeof(vis)); 34 dfs(i,0); 35 for(int j=1;j<=n;++j) 36 { 37 if(j==i) continue; 38 //cout<<vis[j]<<" "; 39 if(vis[j]>1) 40 ans+=cnt(vis[j]); 41 } 42 //cout<<endl; 43 } 44 cout<<ans<<endl; 45 }
E水题
F水题
G - New Year Permutation
思维+并查集+个人SB错误(关了流同步用getchar)
对于每个可以交换的数字集合,按照元素大小排序,到元素对应的集合的时候,从小到大依次取出就ok
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e3; 4 int fa[maxn],a[maxn]; 5 char plat[maxn][maxn]; 6 int n; 7 int findx(int x) 8 { 9 return x==fa[x]?x:fa[x]=findx(fa[x]); 10 } 11 vector<int>per[maxn]; 12 int cnt[maxn],tmp[maxn]; 13 int main() 14 { 15 //ios::sync_with_stdio(0); 16 for(int i=1;i<maxn;++i) fa[i]=i; 17 cin>>n; 18 for(int i=1;i<=n;++i) 19 { 20 cin>>a[i]; 21 } 22 23 for(int i=1;i<=n;++i) 24 { 25 cin>>plat[i]+1; 26 for(int j=1;j<=n;++j) 27 { 28 if(plat[i][j]=='1') 29 { 30 int a=findx(i),b=findx(j); 31 if(a!=b) 32 { 33 fa[b]=a; 34 } 35 } 36 } 37 } 38 for(int i=1;i<=n;++i) tmp[i]=a[i]; 39 for(int i=1;i<=n;++i) 40 { 41 int t=findx(i); 42 per[t].push_back(i); 43 } 44 for(int i=1;i<=n;++i) 45 { 46 sort(per[i].begin(),per[i].end(),[](int x,int y){return a[x]<a[y];}); 47 } 48 49 for(int i=1;i<=n;++i) 50 { 51 int t=findx(i); 52 cout<<a[per[t][cnt[t]++]]<<" "; 53 } 54 }
H - Alyona and the Tree
树形dp+思维+深度遍历图
每个点和每个边都有权值,当两点距离大于子节点长度时,删掉子节点,问最少删除子节点数量
开始没想明白,,,后来发现:设祖先为X,对于每个子节点的len(X,v),如果这个值小于0,那么从这个字节点开始到它的子节点v',肯定有len(X,v')<len(v,v'),所以维护一个max(0,len(X,v))就可以,当这个值大于子节点权值,删掉子节点,如果子节点不是叶子节点,则移除整棵子树。
1 #include <bits/stdc++.h> 2 #define ll long long 3 #define pii pair<int,int> 4 using namespace std; 5 const int maxn=1e5+5; 6 int a[maxn]; 7 int n,ans; 8 vector<pii>G[maxn]; 9 void dfs(int fa,int now,ll maxx) 10 { 11 if(maxx>a[now]) return; 12 for(int i=0;i<G[now].size();++i) 13 { 14 int to=G[now][i].first,v=G[now][i].second; 15 if(to==fa) continue; 16 dfs(now,to,max(maxx+v,1ll*0)); 17 } 18 ++ans; 19 } 20 int main() 21 { 22 ios::sync_with_stdio(0); 23 cin>>n; 24 for(int i=1;i<=n;++i) cin>>a[i]; 25 for(int i=2;i<=n;++i) 26 { 27 int q,w;cin>>q>>w; 28 G[i].push_back({q,w}); 29 G[q].push_back({i,w}); 30 } 31 dfs(-1,1,0); 32 cout<<n-ans;; 33 }
J - Resort
给一个有向图,一些点是特殊点,要求一条最长链使得这条链起点为普通点,终点为特殊点,输出这条链(因为是链所以要求每个普通点出度均为1)。
一开始想复杂了。。。
根据输入我们可以注意到:一个点可以有多条出边,但是最多只有只有一条入边!
所以,我们反向建图:对于每个点,可能有多条入边,但是只能有一条出边
而且对于每个普通点,满足条件的话要保证其源头只有一个特殊点(此时入度为题目中出度,即保证出度为1),所以每个只被遍历一次,复杂度O(n)。
然后找到最长的输出即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e5+5; 4 int in[maxn]; 5 vector<int>G[maxn],ans[maxn]; 6 int n,hot[maxn]; 7 8 void dfs(int h,int now) 9 { 10 ans[h].push_back(now); 11 if(G[now].size()) 12 { 13 int to=G[now][0]; 14 if(hot[to]) return; 15 if(in[to]>1) return; 16 dfs(h,to); 17 } 18 } 19 int main() 20 { 21 ios::sync_with_stdio(0);cin>>n; 22 for(int i=1;i<=n;++i) cin>>hot[i]; 23 for(int i=1;i<=n;++i) 24 { 25 int t;cin>>t; 26 if(t) G[i].push_back(t); 27 ++in[t]; 28 } 29 for(int i=1;i<=n;++i) 30 { 31 if(hot[i]) dfs(i,i); 32 } 33 int maxx=0,maxi; 34 for(int i=1;i<=n;++i) 35 { 36 if(maxx<ans[i].size()) 37 { 38 maxx=ans[i].size(); 39 maxi=i; 40 } 41 } 42 cout<<maxx<<endl; 43 reverse(ans[maxi].begin(),ans[maxi].end()); 44 for(int t:ans[maxi]) 45 cout<<t<<" "; 46 }
L假的三元环
M读清题就会做
N并查集随便搞搞就可以
Odfs二分图染色一下就ok,复杂度O(n)

1 #include <bits/stdc++.h> 2 #define pii pair<int,int> 3 using namespace std; 4 const int maxn=2e5+5; 5 vector<int>G[maxn]; 6 int n,m; 7 int vis[maxn]; 8 inline int no(int a) 9 { 10 return a==1?0:1; 11 } 12 void dfs(int fa,int now,int color) 13 { 14 for(int to:G[now]) 15 { 16 if(to==fa) continue; 17 if(vis[to]==-1) 18 { 19 vis[to]=no(color); 20 dfs(now,to,no(color)); 21 } else{ 22 if(vis[to]==color) 23 { 24 cout<<"-1"; 25 exit(0); 26 } 27 else; 28 } 29 } 30 } 31 int main() 32 { 33 memset(vis,-1,sizeof(vis)); 34 ios::sync_with_stdio(0); 35 cin>>n>>m; 36 for(int i=1;i<=m;++i) 37 { 38 int a,b;cin>>a>>b; 39 G[a].push_back(b); 40 G[b].push_back(a); 41 } 42 for(int i=1;i<=n;++i) 43 { 44 if(G[i].size()>0 && vis[i]==-1) 45 { 46 vis[i]=1; 47 dfs(-1,i,1); 48 } 49 } 50 int num1=0,num0=0; 51 for(int i=1;i<=n;++i) 52 { 53 if(vis[i]==0) ++num0; 54 if(vis[i]==1) ++num1; 55 } 56 cout<<num0<<endl; 57 for(int i=1;i<=n;++i) if(vis[i]==0) cout<<i<<" "; 58 cout<<endl; 59 cout<<num1<<endl; 60 for(int i=1;i<=n;++i) 61 { 62 if(vis[i]==1) cout<<i<<" "; 63 } 64 cout<<endl;; 65 }
总结:
1.我不会子写dijkstra hhhhh(现在会了),对dij有了更深的了解
(1)开始的写法是假堆,(2)不判断是否入队会T飞(或者队列巨长MLE)(3)队列元素是边数级别的
2.
读题很重要!
读题很重要!
读题很重要!
读题没读好细节就开始瞎jb写导致WA好几发
3.写代码要专心,否则后果就是debug+思路混乱+效率低
4.注意long long (*1)
5.图论题能不能发现一下题意中隐藏的一些性质呢?(H,J)