1. 程式人生 > 實用技巧 >2020牛客暑期多校訓練營(第十場)

2020牛客暑期多校訓練營(第十場)

傳送門:https://ac.nowcoder.com/acm/contest/5675

AEIJ

A. Permutation

題意

給定一個質數p,找到一個1~p-1的排列,使得xi+1≡2xi(modp)或者xi+1≡ 3xi(modp)。

題解

打表找規律,可以發現2xi(modp) 會形成若干個環,3xi(modp)也會形成若干個環。如果在x*2中的某個環裡有一個數變成了x*3那麼就會形成另一個環。所以要優先考慮每次*2,下一個*2形成環了就變成*3。優先*3也是可以的,但是要考慮到如果p是3,會有取餘等於0的情況,所以要判斷的時候加一個取模不得零的條件。

程式碼

 1
#include<bits/stdc++.h> 2 using namespace std; 3 4 bool vis[1001000]; 5 vector<int>v; 6 7 int main() 8 { 9 int t; 10 scanf("%d",&t); 11 while(t--){ 12 v.clear(); 13 memset(vis,0,sizeof(vis)); 14 int n; 15 scanf("%d",&n); 16 int
flag=0; 17 v.push_back(1); 18 vis[1]=1; 19 int res=1; 20 for(int i=2;i<n;i++){ 21 if(vis[(res*2)%n]) res*=3; 22 else res*=2; 23 res%=n; 24 if(vis[res]) {flag=1;break;} 25 v.push_back(res); 26 vis[res]++;
27 } 28 if(flag) printf("-1\n"); 29 else { 30 for(int i=0;i<v.size();i++) printf("%d ",v[i]); 31 printf("\n"); 32 } 33 } 34 return 0; 35 }

E.Game

題意

有n列小方塊,每列小方塊有a[i]個,你可以選擇一個位置從右往左推動小方塊,當然如果此位置左邊和上邊也有小方塊,它們會跟著一起移動,如果某個小方塊移動後懸空,他就會落到下面的小方塊上。如果跟著移動的最左邊的小方塊列為1,則不能移動這個位置。問若干次操作之後小方塊的高度最大值的最小值是多少。(看題目的圖就很清楚了

題解

二分答案,每次check的時候如果出現了當前位置移動後最大高度大於mid,則此mid不可行,否則可行。實際上就是在找當前位置的字首和的平均值是否大於mid,大於就不可行,否則可行。

程式碼

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4  
 5 ll a[100100];
 6 ll b[100100];
 7  
 8 bool check(int mid,int n)
 9 {
10     for(int i=0;i<n;i++) b[i]=a[i];
11     ll res=0;
12     for(int i=0;i<n;i++){
13         if(b[i]>mid) res-=b[i]-mid;
14         else res+=mid-b[i];
15         if(res<0) return false;
16     }
17     return true;
18 }
19  
20 int main()
21 {
22     int t;
23     scanf("%d",&t);
24     while(t--){
25         int n;
26         scanf("%d",&n);
27         for(int i=0;i<n;i++) scanf("%lld",&a[i]);
28         int l=0,r=1e9,ans=0;
29         while(l<=r){
30             int mid=l+r>>1;
31             if(check(mid,n)){
32                 ans=mid;
33                 r=mid-1;
34             }
35             else l=mid+1;
36         }
37         printf("%d\n",ans);
38     }
39     return 0;
40 }javascript:void(0);

I. Tournament

題意

有n個隊伍要進行比賽,每兩個隊伍之間要比一場,每個隊伍在他們比賽的第一天來,比賽完的那天走,問怎麼安排比賽可以使得所有隊伍在賽場待的天數總和最少。

題解

糾結於H題,一直沒寫這個題,直播的時候dls:你們真的以為自己能衝的過去嗎 : ) 看著樣例構造的話,第一想法:這不就是雙for嗎,然後就會愉快的wa。那麼怎樣能夠更優呢? 按照上邊的做***發現隊伍的編號越大等的時間就會越長,那麼可以把他們折中一下,讓大家等的時間儘量一樣。按照出題人的思路: •有n個人的日子,至少一天,有至少n-1個人的日子,至少四天。依次類推,可以得到個下界。 • 同時還有另外一個下界,有3個人的日子,至少n(n-1)/2-2天,依次類推。 • 為了達到這個下界,構造的方法就是首先將人分成兩個部分。 • 前後分別內部對打,然後中間將先離場的和最後進場的排在中間。 • 依次往外擴

程式碼

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3  
 4 int main()
 5 {
 6     int t;
 7     scanf("%d",&t);
 8     while(t--){
 9         int n;
10         scanf("%d",&n);
11         for(int i=2;i<=n/2;i++){
12             for(int j=1;j<i;j++){
13                 printf("%d %d\n",j,i);
14             }
15         }
16         for(int i=n/2+1;i<=n;i++){
17             for(int j=1;j<=n-i;j++){
18                 printf("%d %d\n",j,i);
19             }
20         }
21         for(int i=1;i<=n/2;i++){
22             for(int j=n-i+1;j<=n;j++){
23                 printf("%d %d\n",j,i);
24             }
25         }
26         for(int i=n/2+1;i<=n;i++){
27             for(int j=i+1;j<=n;j++){
28                 printf("%d %d\n",j,i);
29             }
30         }
31     }
32     return 0;
33 }

J.Identical Trees

題意

有兩棵形狀一樣的有根樹,分別給出了當前編號的父結點是誰,如果父結點為0,則是根結點。現在要求兩棵樹根的編號得一樣,每個結點父親的編號得一樣,每棵樹編號得是1~n的排列,每次操作可以改變一個結點的編號,問最少需要操作幾次。

題解

首先肯定要使編號一樣的最多,這樣需要改的才最少,然後就可以用樹形dp,轉移的時候用費用流轉移。dp[x][y]表示把第一顆樹的x子樹變成跟第二棵樹的y子樹一樣需要更換的個數。然後轉移到x的父親p跟y的父親q的時候就是他的p跟q的兒子們匹配一下。

程式碼

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 typedef pair<int,int> pii;
  5 typedef pair<ll,ll> pll;
  6 typedef pair<double,double> pdd;
  7 typedef unsigned long long ull;
  8 typedef set<int>::iterator sit;
  9 #define st first
 10 #define sd second
 11 #define mkp make_pair
 12 #define pb push_back
 13 const int inf = 0x3f3f3f3f;
 14 const ll INF = 0x3f3f3f3f3f3f3f3f;
 15 const ll mod = 1000000007;
 16 const int maxn = 2000+10;
 17 const int M = 2e6 + 10;
 18  
 19 int head[maxn];
 20 struct Edge
 21 {
 22     int id,nex;
 23     int w,f;// w 花費 f 流
 24 }edge[M<<2];
 25 int cnt;
 26 void add(int x,int y,int f,int w)
 27 {
 28     edge[cnt].id = y;
 29     edge[cnt].f = f;
 30     edge[cnt].w = w;
 31     edge[cnt].nex = head[x];
 32     head[x] = cnt ++ ;
 33 }
 34 int n;
 35  
 36 int vis[maxn];
 37 int dis[maxn];
 38 int mflow[maxn];
 39 int per[maxn];
 40 queue<int> qq;
 41  
 42 int spfa(int s,int t)
 43 {
 44     for (int i = 0; i<= n ; i++ )
 45     {
 46         vis[i] = 0;
 47         dis[i] = inf;
 48     }
 49     mflow[s] = inf;
 50     qq.push(s);
 51     dis[s] = 0;
 52     vis[s] = 1;
 53     while(!qq.empty())
 54     {
 55         int x=  qq.front();
 56         qq.pop();
 57         vis[x] = 0;
 58         for (int i = head[x]; ~i; i = edge[i].nex)
 59         {
 60             int v = edge[i].id;
 61             if(dis[v] > dis[x] + edge[i].w && edge[i].f)
 62             {
 63                 // printf("111\n");
 64                 dis[v] = dis[x] + edge[i].w;
 65                 per[v] = i;
 66                 mflow[v] = min(mflow[x],edge[i].f);
 67                 if(vis[v])
 68                     continue;
 69                 vis[v] = 1;
 70                 qq.push(v);
 71             }
 72         }
 73     }
 74     if(dis[t] != inf)
 75         return 1;
 76     return 0;
 77 }
 78 void update(int s,int t, int& flow)//flow 流  ans 花費
 79 {
 80     int minn = mflow[t];
 81     for (int i = t; i != s; i = edge[per[i] ^ 1].id)
 82     {
 83         int x = per[i];
 84         edge[x].f -= minn;
 85         edge[x^1].f += minn;
 86     }
 87     flow += minn;
 88 }
 89  
 90 int solve(int s,int t, int& flow)
 91 {
 92     int ans = 0;
 93     while(spfa(s,t))
 94     {
 95         ans += dis[t] * mflow[t];
 96         update(s,t,flow);
 97     }
 98     return ans;
 99 }
100  
101 std::vector<int> vv[2][maxn];
102  
103 string zxbs[2][maxn];
104 void getzxbs(int x,int f)
105 {
106     std::vector<string> vt;
107     zxbs[f][x] += '(';
108     for (int i =0 ; i < vv[f][x].size(); i ++ )
109     {
110         int v = vv[f][x][i];
111         getzxbs(v,f);
112         vt.pb(zxbs[f][v]);
113     }
114     sort(vt.begin(),vt.end());
115     for (int i = 0; i < vt.size(); i ++ )
116     {
117         zxbs[f][x] += vt[i];
118     }
119     zxbs[f][x] += ')';
120 }
121 int dp[maxn][maxn];
122 int N;
123 int bj[maxn];
124 void dfs(int x,int y)
125 {
126     for(int i= 0; i < vv[0][x].size(); i ++ )
127     {
128         int v = vv[0][x][i];
129         for (int j =0 ; j < vv[1][y].size(); j ++ )
130         {
131  
132             int p = vv[1][y][j];
133             if(zxbs[0][v] == zxbs[1][p])
134             {
135                 dfs(v,p);
136             }
137         }
138     }
139     if(vv[0][x].size() == 0)
140     {
141         if(x == y)
142             dp[x][y] = 0;
143         else
144             dp[x][y] = 1;
145         return;
146     }
147  
148     int s =0 , t = 1;
149     int pos = 1;
150     for (int i = 0; i < vv[0][x].size(); i ++ )
151     {
152         int v = vv[0][x][i];
153         bj[v] = ++pos;
154     }
155     for (int i =0 ; i < vv[1][y].size(); i ++ )
156     {
157         int v = vv[1][y][i];
158         bj[v + N] = ++ pos;
159     }
160     n = pos;
161     for (int i = 0; i<= n; i ++ )
162     {
163         head[i] = -1;
164     }
165     cnt = 0;
166     for(int i= 0; i < vv[0][x].size(); i ++ )
167     {
168         int v = vv[0][x][i];
169         for (int j =0 ; j < vv[1][y].size(); j ++ )
170         {
171             int p = vv[1][y][j];
172             if(zxbs[0][v] == zxbs[1][p])
173             {
174                 add(bj[v],bj[p + N],1,dp[v][p]);
175                 add(bj[p + N], bj[v],0,-dp[v][p]);
176             }
177         }
178     }
179     for (int i =0 ; i < vv[0][x].size(); i ++ )
180     {
181         int v= bj[vv[0][x][i]];
182         add(s,v,1,0);
183         add(v,s,0,0);
184     }
185     for (int i =0 ; i < vv[1][y].size(); i ++ )
186     {
187         int v= bj[vv[1][y][i] + N];
188         add(v,t,1,0);
189         add(t,v,0,0);
190     }
191     int p;
192     dp[x][y] = solve(s,t,p);
193     if(x != y)
194         dp[x][y] ++ ;
195 }
196  
197 int main()
198 {
199     int n;
200     scanf("%d",&n);
201     N=  n;
202     int r1,r2;
203     for (int i =1 ; i <= n; i ++ )
204     {
205         int x;
206         scanf("%d",&x);
207         if(x != 0)
208             vv[0][x].pb(i);
209         else
210             r1 = i;
211     }
212     for (int i =1 ; i <= n; i ++ )
213     {
214         int x;
215         scanf("%d",&x);
216         if(x != 0)
217             vv[1][x].pb(i);
218         else
219             r2 = i;
220     }
221     getzxbs(r1,0);
222     getzxbs(r2,1);
223     dfs(r1,r2);
224     printf("%d\n",dp[r1][r2]);
225  
226 }