2019 Wannafly summer camp Day1

 

赛后补题:

  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 }
View Code

总结:

  1.我不会子写dijkstra  hhhhh(现在会了),对dij有了更深的了解

        (1)开始的写法是假堆,(2)不判断是否入队会T飞(或者队列巨长MLE)(3)队列元素是边数级别的

  2.

    读题很重要!

    读题很重要!

    读题很重要!  

  读题没读好细节就开始瞎jb写导致WA好几发

  3.写代码要专心,否则后果就是debug+思路混乱+效率低

  4.注意long long  (*1)

  5.图论题能不能发现一下题意中隐藏的一些性质呢?(H,J)

posted @ 2019-07-31 19:10  codeoos  阅读(204)  评论(0编辑  收藏  举报