首页 > 代码库 > Codeforces Round #287 (Div. 2) 解题报告

Codeforces Round #287 (Div. 2) 解题报告

好久没写题了,底下代码都比较糟糕,将就着看吧。。

 

507A  Amr and Music

要学最多的乐器,所以我们贪心选择时间花费少的。注意这里可以直接用pair,就不必写struct的compare函数了

技术分享
 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5  6 struct ins{ 7     int v, id; 8 } a[110]; 9 bool cmp(ins a, ins b){10     return a.v < b.v;11 }12 int n, k, cnt;13 14 int main()15 {16     scanf("%d %d", &n, &k);17     for (int i = 0; i < n; i++){18         scanf("%d", &a[i].v);19         a[i].id = i;20     }21     sort(a, a+n, cmp);22     cnt = 0;23     int j;24     for (j = 0; j < n; j++){25         cnt += a[j].v;26         if (cnt > k) break;27     }28     printf("%d\n", j);29     for (int p = 0; p < j; p++)30         printf("%d%c", a[p].id+1, p==j-1?\n: );31     return 0;32 }
View Code

 

507B  Amr and Pins

每次以圆周上某位置为中心,任意旋转。通过此操作最多让圆心向任意方向前进2r的距离,也就是说一次step,可以向目标前进d(0<d<=2r)地距离,所以答案就是ceil(dist/r/2)。

因为怕精度的问题,我直接用平方做的比较,结果就WA了几次。。本来是if(dist % (r*2)) ans++,我写的 if (dist^2 % (4*r^2)) ans++,实际上两者不等价。。本来是无法整除的,平方后可能可以整除。结果后来写的二分。。因为平方太大还爆longlong了。。

技术分享
 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<cmath> 5 using namespace std; 6  7 int r, x, y, xx, yy; 8  9 int main()10 {11     scanf("%d %d %d %d %d", &r, &x, &y, &xx, &yy);12     long long dis2 = (long long)(xx - x) * (xx - x)13                +(long long)(yy - y) * (yy - y);14     long long ll = 0, rr = 150000, ans = 0;15     while(ll <= rr){16         long long m = (ll + rr) / 2;17         long long d = (m*r*2);18         long long tmpd, tmpdis2;19         if (d > 2100000000){20             tmpd = d;21             tmpdis2 = sqrt(double(dis2));22         }23         else tmpd = d * d, tmpdis2 = dis2;24         if (tmpd >= tmpdis2){25             ans = m;26             rr = m - 1;27         }28         else ll = m + 1;29     }30     cout << ans << endl;31     return 0;32 }
View Code


瞥了眼tourist的代码,虽然不是最简单的写法,但感觉写法挺值得借鉴的(对于这题,为什么对,我也没想太清楚。。)

技术分享
 1 int main() { 2   long long r, x, y, xx, yy; 3   cin >> r >> x >> y >> xx >> yy; 4   long long dist = (x - xx) * (x - xx) + (y - yy) * (y - yy); 5   long long step = 4 * r * r; 6   long long res = (dist + step - 1) / step;    //整数向上取整的除法 7   long long ans = sqrt(1.0 * res);                //整数向上取整的开根号 8   while (ans * ans < res) ans++; 9   while (ans > 0 && (ans - 1) * (ans - 1) >= res) ans--;10   cout << ans << endl;11   return 0;12 }
View Code

 

507C  Guess Your Way Out!

题意:给一颗高度为h的满二叉树(0..h),第n个叶子(1<=n<=2^h)为出口,按照LRLR的序列以及一定规则来遍历树,问找到出口前访问过多少个点。

分析:按照所给定的规则,走错一步,我们将访问完整棵子树,所以答案要多加子树的点数。实际上走向出口的正确序列可以直接由n-1的二进制表示得到,比照正确序列和LRLRLR,错的时候加上多余的点就可以了。

技术分享
 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 using namespace std; 6  7 int h, flag; 8 int p[110]; 9 long long n, ans, add;10 int main()11 {12     scanf("%d %I64d", &h, &n);13     n--; ans = 0; flag = 0;14     add = 1; for (int i = 0; i < h; i++) add = add * 2;15     int len = 0; memset(p, 0, sizeof(p));16     while(n){17         p[len++] = n & 1;18         n = n / 2;19     }20     for (int i = h-1; i >= 0; i--){21         if (p[i] != flag) ans = ans + add;    //flag为0向左,为1向右22         else{23             ans ++;24             flag ^= 1;    //走对时才调整方向25         }26         add = add / 2;27     //    cout << ans << ‘ ‘ << i << ‘ ‘ << add << endl;28     }29     cout << ans << endl;30     return 0;31 }
View Code

 

507D  The Maths Lecture

题意:给定n,m,k,问长度为n,没有前导0的数中,有多少个满足:存在某个后缀y, y>0且无前导0, 满足y mod k = 0。输出满足条件的数的个数mod m

分析:数位dp。dp[i][j]表示长度为i,无前导0的数,且没有后缀y能满足y mod k = 0,且本身mod k = j 的数的个数。这样就可以通过不断在左侧加上新的数,进行转移,对于mod k = 0的数,即dp[i][0],就可以累加他们到答案里。

然后需要注意,已经mod k=0的就不用转移了,否则会重复计算(也就满足dp[][]定义),从而导致全为0的后缀会被遗漏,还有p000suffix,这种中间有某些位为0的也会被遗漏,所以修改dp[i][j]的定义为长度<=i的自然数(不包括0)...然后就可以了

实际上,最后dp[i][j]表示长度不超过i的自然数(不包括0),没有后缀满足mod k = 0,自身mod k = j 的数的个数。

技术分享
 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 using namespace std; 5  6 long long n, m, k, ans; 7 long long dp[1100][110]; 8  9 int main()10 {11     cin >> n >> k >> m;12     for (int i = 1; i < 10; i++) dp[1][i%k] ++;    //初始化长度为1的,注意没有013     long long f = 1;14     for (int i = 1; i < n; i++){15         f = f * 10 % k;        //10的幂次用f来代替16         for (int j = 0; j < k; j++){17             int add = j==0? 1: dp[i][j];    //之前为0的只能加上0000..18             for (int p = 1; p < 10; p++){19                 dp[i+1][(j+p*f)%k] += add;20                 dp[i+1][(j+p*f)%k] %= m;21             }22         }23         for (int j = 1; j < k; j++){24             dp[i+1][j] += dp[i][j];25             dp[i+1][j] %= m;26         }27     }28     ans = dp[n][0] % m; f = 9;29     for (int i = n-1; i > 0; i--){30         ans += dp[i][0] * f % m;31         ans %= m; f = f * 10 % m;32     }33     cout << ans << endl;34     return 0;35 }
View Code

 

507E  Breaking Good

题意:给一个n点m边的连通无向图,每个边有0和1两种属性,需要你求1到n的最短路,以及:影响的道路数 num = 不在最短路上且属性为1的边的个数+在最短路上且属性为0的边的个数 尽量少。

分析:tot[i]表示属性为i的边的总数,used[i]表示最短路上属性为i的边的个数,dis[i]表示到i点的最短路,所以num = (tot[1] - used[1]) + (dis[n] - used[1]),为了num尽量小,used[1]要尽量大。所以就是两个关键字的最短路了。

代码较丑,轻拍

技术分享
 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<set> 5 using namespace std; 6  7  8 struct edge{ 9     int v, w, n;10 } e[200100];11 12 int esize;13 int en[100100];14 void insert(int x, int y, int z){15     e[esize].v = y;16     e[esize].w = z;17     e[esize].n = en[x];18     en[x] = esize++;19 }20 21 22 int n, m;23 int tot[2];24 int d[100100], p[100100], c[100100]; bool vis[100100];25 int q[8000000];26 int aa[100100], bb[100100], cc[100100];27 void spfa(){28     int head, tail;29     head = tail = 0;30     memset(d, 127, sizeof(int)*(n+1));31     memset(vis, 0, sizeof(bool)*(n+1));32     p[1] = d[1] = c[1] = 0; vis[1] = 1;33     q[tail++] = 1;34     while(head != tail){35         int u = q[head++];36         for (int t = en[u]; t != -1; t = e[t].n){37             int v = e[t].v;38             if (d[v] > d[u] + 1 || ((d[v] == d[u]+1) && (c[v] < c[u] + e[t].w))){39                 d[v] = d[u] + 1;40                 c[v] = c[u] + e[t].w;41                 p[v] = u;42                 if (!vis[v]){43                     vis[v] = true;44                     q[tail++] = v;45                 }46             }47         }48         vis[u] = false;49     }50     printf("%d\n", d[n]-c[n]+tot[1]-c[n]);51     set<pair<int, int> > s;52     int cur = n, pre;53     while(cur != 1){54         pre = cur; cur = p[cur];55         s.insert(make_pair(cur, pre));56         s.insert(make_pair(pre, cur));57     }58     for (int i = 0; i < m; i++){59         if (s.find(make_pair(aa[i], bb[i])) != s.end()){60             if (cc[i] == 0) printf("%d %d 1\n", aa[i], bb[i]);61         }62         else if (cc[i] == 1) printf("%d %d 0\n", aa[i], bb[i]);63     }64 65 }66 int main()67 {68     scanf("%d %d", &n, &m);69     esize = 0; memset(en, -1, sizeof(int) * (n+1));70     tot[0] = tot[1] = 0;71     for (int i = 0, x, y, z; i < m; i++){72         scanf("%d %d %d", &x, &y, &z);73         tot[z] ++;74         insert(x, y, z);75         insert(y, x, z);76         aa[i] = x, bb[i] = y, cc[i] = z;77     }78     spfa();79     return 0;80 }
View Code

 

Codeforces Round #287 (Div. 2) 解题报告