1. 程式人生 > >ACM團隊周賽題解(2)

ACM團隊周賽題解(2)

latin 直接 ios heap cal bsp font 初始 color

拉了CF583和CF486的兩套div2題目

還是先貼宏定義部分

#define MAXN 1000000+5
#define MOD 1000000007
#define PI (acos(-1.0))
#define EPS 1e-6
#define MMT(s,a) memset(s, a, sizeof s)
#define GO(i,a,b) for(int i = (a); i < (b); ++i)
#define GOE(i,a,b) for(int i = (a); i <= (b); ++i)
#define OG(i,a,b) for(int i = (a); i > (b); --i)
#define OGE(i,a,b) for(int i = (a); i >= (b); --i)


A - Asphalting Roads(CF-583A)

題意就是n條水平路,n條豎直路,構成井字形狀。然後第i天會到(xi,yi)這個路口,如果這個路口得兩條路都沒有被染色,就輸出這天並把兩個路口都染上顏色,否則跳到下一天。

輸出所有可以染色得天數。

題目思路:標記遍歷即可

 1 int main(){
 2     ios_base::sync_with_stdio(false), cout.tie(0), cin.tie(0);
 3     int n,x,y;
 4     cin>>n;
 5     int mp1[55] = {0
},mp2[55] = {0}; 6 GO(i,0,n*n){ 7 cin>>x>>y; 8 if(mp1[x] == 0 && mp2[y] == 0){ 9 cout << i+1 << " "; 10 mp1[x] = mp2[y] = 1; 11 } 12 } 13 cout << endl; 14 15 return 0; 16 }

B - Robot‘s Task(CF-583B)

題意就是最開始從左往右走,如果現在值Num比a[i]大,則Num+1,否則跳過他,走到盡頭如果有數沒有經過,則轉向再次走,已經走過的地方不能再走。

Num初始值為0,問至少轉向幾次。

思路:模擬即可

 1 int main(){
 2     ios_base::sync_with_stdio(false), cout.tie(0), cin.tie(0);
 3     int n;
 4     int a[1005] = {0},vis[1005] = {0};
 5     cin>>n;
 6     GOE(i,1,n){
 7         cin>>a[i];
 8     }
 9     bool flag = true;
10     int cnt = n,ans = 0,num = 0;
11     while(cnt > 0){
12         if(flag){
13             GOE(i,1,n){
14                 if(!vis[i] && num >= a[i]){
15                     vis[i] = 1;
16                     num++;
17                     cnt--;
18                 }
19             }
20         }
21         else{
22             OGE(i,n,1){
23                 if(!vis[i] && num >= a[i]){
24                     vis[i] = 1;
25                     num++;
26                     cnt--;
27                 }
28             }
29         }
30         flag = !flag;
31         if(cnt > 0)
32             ans++;
33     }
34     cout << ans << endl;
35 
36     return 0;
37 }

C - GCD Table(CF-583C)

給你一個打亂了的GCD表,問是哪些值構成的。

思路:這n個數一定就是對角線上的數,直接降序排列然後暴力找,每次找到的最大的數一定是其中一個數,然後求出它與已經求出的所有數的gcd在隊列中去掉兩個這個gcd數,保證所有大於等於下一個數字的gcd一定都被去掉了,剩下的最大的又是要找的數。

額外定義

template<typename T>
using maxHeap = priority_queue<T, vector<T>, less<T> >;

template<typename T>
inline T gcd(T a, T b){ return b==0 ? a : gcd(b,a%b); }

代碼

 1 int main(){
 2     ios_base::sync_with_stdio(false), cout.tie(0), cin.tie(0);
 3     int n,k = 0,temp,num;
 4     int a[250050],b[250050];
 5     cin>>n;
 6     GOE(i,1,n*n){
 7         cin>>a[i];
 8     }
 9     sort(a+1,a+1+n*n);
10     maxHeap<int> q;
11     OG(i,n*n,0){
12         if(!q.empty())
13             temp = q.top();
14         else
15             temp = 0;
16         if(a[i] == temp){
17             q.pop();
18             continue;
19         }
20         GO(j,0,k){
21             num = gcd(b[j],a[i]);
22             q.push(num);
23             q.push(num);
24         }
25         b[k++] = a[i];
26     }
27     GO(i,0,k)
28         cout << b[i] << " ";
29     cout << endl;
30     
31     return 0;
32 }

F - Calculating Function(CF-486A)

題意就是按照他給的公式輸出F(n);

思路:可以推出n為偶數是F(n) = n/2,否則F(n) = n/2 - n;

代碼

 1 int main(){
 2     ios_base::sync_with_stdio(false), cout.tie(0), cin.tie(0);
 3     ll n;
 4     cin>>n;
 5     if (n&1)
 6         cout << n/2 - n << endl;
 7     else
 8         cout << n/2 << endl;
 9 
10     return 0;
11 }

G - OR in Matrix(CF-486B)

題目就是說bij為i行和j列的值OR操作的結果,現在給你操作後的表,要你求操作前的表。

思路:如果bij = 0,則證明i行和j列全是0,如果是1,則證明i行和j列必須有一個1,所以先把所有值設為1,按照題目把某些行列變為0,再判斷一遍是否滿足題意即可

代碼

 1 int main(){
 2     ios_base::sync_with_stdio(false), cout.tie(0), cin.tie(0);
 3     int n,m;
 4     int a[105][105],b[105][105];
 5     fill(b[0],b[0]+105*105,1);
 6     cin>>n>>m;
 7     GOE(i,1,n){
 8         GOE(j,1,m){
 9             cin>>a[i][j];
10             if(a[i][j] == 0){
11                 GOE(ii,1,n)
12                     b[ii][j] = 0;
13                 GOE(jj,1,m)
14                     b[i][jj] = 0;
15             }
16         }
17     }
18 
19     GOE(i,1,n){
20         GOE(j,1,m){
21             if(a[i][j] == 1){
22                 int flag = 0;
23                 GOE(ii,1,n){
24                     if(b[ii][j] == 1){
25                         flag = 1;
26                         break;
27                     }
28                 }
29                 GOE(jj,1,m){
30                     if(b[i][jj] == 1){
31                         flag = 1;
32                         break;
33                     }
34                 }
35                 if(!flag){
36                     cout << "NO" << endl;
37                     exit(0);
38                 }
39             }
40         }
41     }
42 
43     cout << "YES" << endl;
44     GOE(i,1,n){
45         GOE(j,1,m)
46             cout << b[i][j] << " ";
47         cout << endl;
48     }
49 
50     return 0;
51 }

H - Palindrome Transformation(CF-486C)

題意就是4種操作,最開始在k位置操作,問最少操作多少次使得原串變成回文串。

思路:因為是對稱的,我們先不要管最開始在哪個位置,遍歷即可,當a[i] != a[n-i-1]時候,我們再想是變a[i]還是變另一個,然後答案加上這個值。同時往容器中加上從k走到i遠還是走到n-i-1近。

最後排序,答案加上最遠距離於最近距離之差再加上這兩者距離k最近的距離即可。

為什麽只需要不需要管k的位置,因為k無論在哪裏,我們都需要把所有不符合的字符走到,所以這裏得花掉最遠距離和最近距離的差,同時我們最開始在k,需要走到最近的位置開始遍歷上一段距離,所以最終答案就是

  ans = 每個不合格字符的操作次數 + 不合格字符的區間長度 + 從k位置走到這個區間的某一端點的距離;

因為不管你的k是否在這個區間內,都需要遍歷一遍這個區間。

 1 int main(){
 2     ios_base::sync_with_stdio(false), cout.tie(0), cin.tie(0);
 3     int n,k;
 4     string s;
 5     vector<int> q;
 6     cin>>n>>k>>s;
 7     int len = n/2,ans = 0;
 8     GO(i,0,len){
 9         if(s[i] != s[n-1-i]){
10             int tp = abs(s[i] - s[n-1-i]);
11             tp = min(tp,26-tp);
12             ans += tp;
13             if(tp)
14                 q.PB((abs(i+1-k) < abs(n-i-k)) ? i+1 : n-i);
15         }
16     }
17     int cnt = q.size();
18     if(q.empty())
19         cout << ans << endl;
20     else{
21         sort(q.begin(),q.end());
22         ans += q[cnt-1] - q[0] + min(abs(q[cnt-1]-k),abs(q[0]-k));
23         cout << ans << endl;
24     }
25     return 0;
26 }

D題E題時間關系暫時不補了。

ACM團隊周賽題解(2)