1. 程式人生 > >Codeforces Round #503(div2) 做題記錄

Codeforces Round #503(div2) 做題記錄

一次 ORC force eof fine break bits 滿足 ems

前幾天有點咕,馬上題解會跟上~

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\n",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\n",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\n",pos);
 8     fflush(stdout);
 9     scanf("%d",&x);
10     printf("? %d\n",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\n");
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\n",l);
28         return 0;
29     }
30     if(fr==0)
31     {
32         printf("! %d\n",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\n",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\n",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?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\n",cnt);
29     for(int i=1;i<=cnt;++i)printf("%d ",ans[i]);
30     return 0;
31 }

Codeforces Round #503(div2) 做題記錄