暑期集训第十三天(7-4)题解及总结

小总结:

今天下午正好赶上洛谷的一次比赛,结果和我一起参加的都有分,只有我一下午一道题也没有做出来还把脑子弄傻了颓了一下午???

今天longdie再次骑到了我和lc的前面,还险些AK,我只刚刚上了300,看来我是越来越菜了......

对了,纪念一下集训以来第一次的上300(我才不会说是因为这次题目简单)

 

 

 T1:侦查

 

这道题其实就是一个签到题......tarjan板子没忘掉的应该都能做对吧,就是送分题,可能老姚看我们最近分数偏低友情赠送了100pts?_?

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=1e6+10;
 4 struct Node{
 5     int next,to;
 6 }edge[N];
 7 int Head[N],tot;
 8 void Add(int x,int y){
 9     edge[++tot].to=y;
10     edge[tot].next=Head[x];
11     Head[x]=tot;
12 }
13 int dfn[N],low[N],dfn_cnt,scc_cnt,belong[N],w[N],siz[N],peo[N];
14 stack<int>sta;
15 void tarjan(int u){
16     dfn[u]=low[u]=++dfn_cnt;
17     sta.push(u);
18     for(int i=Head[u];i;i=edge[i].next){
19         int v=edge[i].to;
20         if(!dfn[v]){
21             tarjan(v);
22             low[u]=min(low[u],low[v]);
23         }
24         else if(!belong[v]) low[u]=min(low[u],dfn[v]);
25     }
26     if(dfn[u]==low[u]){
27         scc_cnt++;
28         int t;
29         do{
30             t=sta.top();sta.pop();
31             belong[t]=scc_cnt;siz[scc_cnt]++;
32             peo[scc_cnt]+=w[t];
33         }while(t!=u);
34     }
35 }
36 int main(){
37     int n,m;
38     scanf("%d%d",&n,&m);
39     for(int i=1;i<=n;++i) scanf("%d",&w[i]);
40     for(int i=1;i<=m;++i){
41         int x,y;
42         scanf("%d%d",&x,&y);
43         Add(x,y);Add(y,x);
44     }
45     for(int i=1;i<=n;++i)
46         if(!dfn[i]) tarjan(i);
47     int ans1=0,ans2=0,cnt1,cnt2;
48     for(int i=1;i<=scc_cnt;++i){
49         ans1=max(ans1,siz[i]);
50         ans2=max(ans2,peo[i]);
51     }
52     for(int i=1;i<=n;++i){
53         if(siz[belong[i]]==ans1){
54             cnt1=belong[i];
55             break;
56         }
57     }
58     for(int i=1;i<=n;++i){
59         if(peo[belong[i]]==ans2){
60             cnt2=belong[i];
61             break;
62         }
63     }
64     for(int i=1;i<=n;++i)
65         if(belong[i]==cnt1) printf("%d ",i);
66     puts("");
67     for(int i=1;i<=n;++i)
68         if(belong[i]==cnt2) printf("%d ",i);
69     puts("");
70     return 0;
71 }

T2:借书

 

 

 这道题乍一看还以为是dp...状压30pts,线性60pts,满分考场上没有想到正解,于是只写了一个60pts的线性dp,考完才知道前十一个人之中好像只有我没有把这个题的分拿满......

看到这道题考虑盘古开天辟地之前我们做过的一道叫做最大值最小化的题目,那道题就是一道二分答案的板子题(其实这道题也算),考虑对原数组进行排序使之具有单调性,之后运用差分的思想对原数组进行处理,枚举可行的答案,再judge一下判断是否符合条件就可以了

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=1e5+10;
 4 int n,m,a[N],cf[N],Max;
 5 bool check(int x){
 6     int cnt=0,ch=0;
 7     for(int i=1;i<n;++i){
 8         ch+=cf[i];
 9         if(ch>=x){
10             cnt++;ch=0;
11         }
12     }
13     if(cnt>=m-1) return true;
14     return false;
15 }
16 int main(){
17     scanf("%d%d",&n,&m);
18     for(int i=1;i<=n;++i) scanf("%d",&a[i]),Max=max(Max,a[i]);
19     sort(a+1,a+n+1);
20     for(int i=1;i<n;++i) cf[i]=a[i+1]-a[i];
21     int l=0,r=Max;
22     while(l<=r){
23         if(l==r-1){
24             if(check(r)){
25                 l=r;
26             }break;
27         }
28         int mid=(l+r)>>1;
29         if(check(mid)) l=mid;
30         else r=mid;
31     }
32     printf("%d\n",l);
33     return 0;
34 }

T3:搜城探宝

 

 

 这一道题乍一看和之前做过的一道名叫"宝藏"的紫题描述和数据范围挺像的,但是这道题多了一道烦人的传送门,于是原来的状压做法就被毙掉了,但是还是可以用状压来做,考虑把传送门也当作一把钥匙,那么我们就最多可以到达k+1个点,由于传送门的性质,最后形成的一定是有一个或两个联通块的图,于是枚举所有情况进行判断,计算联通块的数量即可,在考场上我没考虑根节点的情况,导致有两个点答案多了一,看来自己的思维还是不够缜密呀QAQ.

当然老师也讲了另一种做法(就是比状压难想还难写难调),这里直接贴一个链接吧.

https://www.cnblogs.com/hbhszxyb/p/13234472.html

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define int long long
 4 const int N=25;
 5 vector<int>edge[N];
 6 int count(int x){
 7     int cnt=0;
 8     while(x){
 9         if(x & 1) cnt++;
10         x>>=1;
11     }
12     return cnt;
13 }
14 int sur[N];
15 void mark(int x){
16     int cnt=1;
17     while(x){
18         if(x & 1) sur[cnt]=1;
19         x>>=1;cnt++;
20     }
21 }
22 int w[N],vis[N];
23 int n,k,ans=0;
24 void dfs(int now){
25     vis[now]=1;
26     for(int i=0;i<edge[now].size();++i){
27         int v=edge[now][i];
28         if(!sur[v]) continue;
29         if(!vis[v]) dfs(v);
30     }
31 }
32 bool Judge(int x){
33     memset(sur,0,sizeof(sur));
34     memset(vis,0,sizeof(vis));
35     mark(x);
36     int cnt=0;
37     for(int i=1;i<=n;++i){
38         if(sur[i]&&!vis[i]){
39             dfs(i);cnt++;
40         }
41     }
42     if(cnt==2 && (!sur[1])) return false;
43     if(cnt>2) return false;
44     return true;
45 }
46 int cal(int x){
47     int cnt=1,ans=0;
48     while(x){
49         if(x & 1) ans+=w[cnt];
50         x>>=1;cnt++;
51     }
52     return ans;
53 }
54 signed main(){
55     scanf("%lld%lld",&n,&k);
56     int ed=(1<<n)-1;
57     for(int i=1;i<n;++i){
58         int x,y;
59         scanf("%lld%lld",&x,&y);
60         edge[x].push_back(y);
61         edge[y].push_back(x);
62     }
63     for(int i=1;i<=n;++i) scanf("%lld",&w[i]);
64     for(int i=0;i<=ed;++i){
65         if(count(i)>k+1) continue;
66         if(!Judge(i)) continue;
67         ans=max(ans,cal(i)); 
68     }
69     printf("%lld\n",ans);
70     return 0;
71 }

T4:MM不哭

 

 

 (成功在一道做过的题上栽了20pts)

这道题记得还是老师在刚刚集训的时候就推荐我们做过,但是老师后来自己忘了???

 

(有图为证)

这道类似的题目之前我写过,这里就不再进行复述了。基本上把转移方程推出来就没有什么大的问题了,(然而我还是没能拿满分

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 const int N=5000+5;
 5 using namespace std;
 6 int sum[N][N],cost[N],dp[N][N][2];
 7 struct Node{
 8     int loc,pow;
 9 }a[N];
10 int main(){
11     int n,c;
12     scanf("%d%d",&n,&c);
13     for(int i=1;i<=n;++i){
14         scanf("%d%d",&a[i].loc,&a[i].pow);
15     }
16     for(int i=1;i<=n;++i){
17         sum[i][i]=a[i].pow;
18         for(int j=i+1;j<=n;++j)
19             sum[i][j]=sum[i][j-1]+a[j].pow;
20     }
21     memset(dp,0x3f,sizeof(dp));
22     if(c>=2){
23         dp[c-1][c][0]=(a[c].loc-a[c-1].loc)*(sum[1][c-1]+sum[c+1][n]);
24     }
25     if(c<=n-1){
26         dp[c][c+1][1]=(a[c+1].loc-a[c].loc)*(sum[1][c-1]+sum[c+1][n]);
27     }
28     for(int len=3;len<=n;++len)
29         for(int l=1;l<=n-len+1;++l){
30             int r=l+len-1;
31             dp[l][r][0]=min(dp[l+1][r][0]+(a[l+1].loc-a[l].loc)*(sum[1][l]+sum[r+1][n]),dp[l+1][r][1]+(a[r].loc-a[l].loc)*(sum[1][l]+sum[r+1][n]));
32             dp[l][r][1]=min(dp[l][r-1][0]+(a[r].loc-a[l].loc)*(sum[1][l-1]+sum[r][n]),dp[l][r-1][1]+(a[r].loc-a[r-1].loc)*(sum[1][l-1]+sum[r][n]));
33         }
34     printf("%d\n",min(dp[1][n][0],dp[1][n][1]));
35     return 0;
36 }

一些二分答案的基础题目:

通过今天第二体40pts的丢失,我成功的认识到了自己在二分答案上的不足(其实从开始学就没好过),今天通过练习发现这还是比较简单的,就是写好Judge函数,控制好左右区间的初值和变化就没有什么大的问题了(千万注意左右区间别跳反了,千万注意!!!)。

推荐模板练习:P1182 数列分段 Section II,P1577 切绳子(卡精度十分恶心)

模板:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=1e6+10;
 4 int a[N];
 5 int n,m,l,r;
 6 bool Judge(int x){
 7     int now=0,cnt=0;
 8     for(int i=1;i<=n;++i){
 9         if(now+a[i]<=x) now+=a[i];
10         else{
11             cnt++;now=a[i];
12         }
13     }
14     if(cnt>=m) return true;
15     return false;
16 }
17 int main(){
18     scanf("%d%d",&n,&m);
19     for(int i=1;i<=n;++i){
20         scanf("%d",&a[i]);
21         r+=a[i];l=max(l,a[i]);
22     }
23     while(l<=r){
24         int mid=(l+r)>>1;
25         if(Judge(mid)) l=mid+1;
26         else r=mid-1;
27     }
28     printf("%d\n",l);
29     return 0;
30 }

总结:

在今天下午的模拟赛之前我们都是抱着只拿50pts的目标去的,但是好像只有我没能达成???

longdie大佬还把第一道题A了,(虽然考完发现只是一道黄题),赛后奖励之中好像我们这里的基本都和1RMB的奖励擦肩而过了(也许lc的第一题再跑慢一些少拿些分就可以拿奖了???)

今天晚上有一个体活课,宿舍的热水终于来了......晚上持续颓废中(下午脑子用傻了).......

希望明天能更好吧。

 

posted @ 2020-07-04 21:26  19502-李嘉豪  阅读(153)  评论(0编辑  收藏  举报