Codeforces Round #503(div2) 做题记录

前几天有点咕,马上题解会跟上~

A.

题意:

有n个楼,每个楼有h层,相邻两个楼在(a,b)之间有通道

k次询问,每次问(tA,fA)到(tB,fB)(t为楼的编号,f为楼层)的最短路

题解:

如果不在(a,b)层之间那先爬到离他最近的(a,b)层之间的楼层

然后通过通道直接走,先走到tB走到对应楼层

注意tA=tB时特判

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 int n,h,a,b,q;
 5 int main()
 6 {
 7     scanf("%d%d%d%d%d",&n,&h,&a,&b,&q);
 8     while(q--)
 9     {
10         int t1,f1,t2,f2;
11         int ans=0;
12         scanf("%d%d%d%d",&t1,&f1,&t2,&f2);
13         if(t1==t2)
14         {
15             printf("%d
",abs(f2-f1));
16             continue;
17         }
18         ans+=abs(t2-t1);
19         int now=f1;
20         if(f1<a)ans+=abs(f1-a),now=a;
21         else if(f1>b)ans+=abs(f1-b),now=b;
22         ans+=abs(now-f2);
23         printf("%d
",ans);
24     }
25     return 0;
26 }

B.

题意:

给你一个n个点的基环内向树,询问从每个点出发第一个走到的到过一次的点是什么

题解:

n很小,暴力模拟

 1 #include<bits/stdc++.h>
 2 #define maxn 1005
 3 using namespace std;
 4 int n;
 5 int p[maxn];
 6 bool vis[maxn];
 7 int main()
 8 {
 9     scanf("%d",&n);
10     for(int i=1;i<=n;++i)scanf("%d",&p[i]);
11     for(int i=1;i<=n;++i)
12     {
13         int u=i;
14         memset(vis,0,sizeof(vis));
15         while(!vis[u])vis[u]=1,u=p[u];
16         printf("%d ",u);
17     }
18     return 0;
19 }

C.

题意:

有n个选民,m个党派

你要给一些选民钱,让他们转投1号党派的票

每个选民有一个ci和一个pi,表示让他转投的钱数和他原本投的党派

然后要让1号党派获胜,最少要用多少钱

题解:

枚举其他党派的人数上限

然后把其他党派中人数超过这个上限的强行加到1号中(当然是贪心找最小的加)

如果不超过的另外开个数组

最后sort一下,选最小的几个

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define maxn 3005
 4 using namespace std;
 5 int n,m;
 6 int p[maxn],c[maxn];
 7 vector<int> val[maxn];
 8 int num[maxn];
 9 int a[maxn],cnt;
10 int main()
11 {
12     scanf("%d%d",&n,&m);
13     for(int i=1;i<=n;++i)
14     {
15         scanf("%d%d",&p[i],&c[i]);
16         val[p[i]].push_back(c[i]);
17     }
18     for(int i=1;i<=m;++i)sort(val[i].begin(),val[i].end());
19     ll ans=1e15;
20     for(int i=n;i>=0;--i)
21     {
22         ll res=0,tot=val[1].size();
23         cnt=0;
24         for(int j=2;j<=m;++j)if(val[j].size()>i)
25         {
26             for(int k=0;k<val[j].size()-i;++k)
27             {
28                 res+=val[j][k];++tot;
29             }
30         }
31         for(int j=2;j<=m;++j)
32         {
33             int mind=val[j].size()-i;
34             for(int k=max(mind,0);k<val[j].size();++k)
35             {
36                 a[++cnt]=val[j][k];
37             }
38         }
39         sort(a+1,a+cnt+1);
40         for(int j=1;j<=cnt;++j)
41         {
42             if(tot>i)break;
43             tot++;res+=a[j];
44         }
45         ans=min(ans,res);
46     }
47     cout<<ans<<endl;
48     return 0;
49 }

D.

题意:

交互题

给你一个环,每个值和左右数值的差值是±1

然后你不知道每个点的值

你可以询问每个点的值,求a[i]=a[i+n/2]的位置

题解:

考虑60次询问,大概logn级别

然后令f(x)=a[x]-a[x+n/2]

这个东西在x∈[1,n/2]范围内单调

二分一下就好了

(比赛的时候边界写挂了导致fst QAQ)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n;
 4 int ask(int pos)
 5 {
 6     int x,y;
 7     printf("? %d
",pos);
 8     fflush(stdout);
 9     scanf("%d",&x);
10     printf("? %d
",pos+n/2);
11     fflush(stdout);
12     scanf("%d",&y);
13     return x-y;
14 }
15 int main()
16 {
17     scanf("%d",&n);
18     if(n&1)
19     {
20         printf("! -1
");
21         return 0;
22     }
23     int l=1,r=n/2;
24     int fl=ask(l),fr=ask(r);
25     if(fl==0)
26     {
27         printf("! %d
",l);
28         return 0;
29     }
30     if(fr==0)
31     {
32         printf("! %d
",r);
33         return 0;
34     }
35     if(fl>0&&fr<0)
36     {
37         while(l<=r)
38         {
39             int mid=(l+r)>>1;
40             int t=ask(mid);
41             if(t==0)
42             {
43                 printf("! %d
",mid);
44                 return 0;
45             }
46             if(t>0)l=mid+1;else r=mid-1;
47         }
48     }
49     if(fl<0&&fr>0)
50     {
51         while(l<=r)
52         {
53             int mid=(l+r)>>1;
54             int t=ask(mid);
55             if(t==0)
56             {
57                 printf("! %d
",mid);
58                 return 0;
59             }
60             if(t>0)r=mid-1;else l=mid+1;
61         }
62     }
63     puts("! -1");
64     return 0;
65 }

E.

题意:

给你一个有向图(无自环),你需要构造一个点集Q,满足:

x∈Q,对任意边(x,y)或(y,x),y∉Q

x∉Q,dist(x,Q)<=2(x到Q内任意一点的距离)

题解:

先从前向后遍历一遍

对于一个没有访问过的点u(vis[u]==0),把从u走一步能到达的点v标记上vis[v]=1,并把u暂时加入点集(used[u]==0)

然后考虑反向遍历一遍,如果used[u]==1,那么把u走一步能到的点v踢出点集

 1 #include<bits/stdc++.h>
 2 #define maxn 1000005
 3 using namespace std;
 4 int n,m;
 5 vector<int> g[maxn],gg[maxn];
 6 bool vis[maxn],used[maxn];
 7 int ans[maxn];
 8 int main()
 9 {
10     scanf("%d%d",&n,&m);
11     for(int u,v,i=1;i<=m;++i)
12     {
13         scanf("%d%d",&u,&v);
14         g[u].push_back(v);
15         gg[v].push_back(u);
16     }
17     for(int u=1;u<=n;++u)if(!vis[u])
18     {
19         used[u]=1;
20         for(int j=0;j<g[u].size();++j)vis[g[u][j]]=1;
21     }
22     int cnt=0;
23     for(int u=n;u;--u)if(used[u])
24     {
25         ans[++cnt]=u;
26         for(int j=0;j<g[u].size();++j)used[g[u][j]]=0;
27     }
28     printf("%d
",cnt);
29     for(int i=1;i<=cnt;++i)printf("%d ",ans[i]);
30     return 0;
31 }
原文地址:https://www.cnblogs.com/uuzlove/p/9494223.html