TopCoder SRM 570 题解

官方题解在 http://apps.topcoder.com/wiki/display/tc/SRM+570?focusedCommentId=103450246

DIV2的前两题比较简单, 忽略

DIV2 第三题 1000, 题意是: 给一个N个节点的树(共有N - 1条边), 要求是从这些点中抽取一些点(可以一个也不选), 保证抽取的点也是一颗树。

一看这个题的结果非常大, 枚举所有可能的做法必定超时(O(2**50)),  观察到,可以通过树的递推关系来计算父节点的数目: 令dp[i]表示以i为根, 并且含有i的个数

含有某一个节点i的子树的数目: dp[i] = multi(dp[children of i] + 1),其中1表示 子树可以为空。

最后再计算 sum(dp[i]) for i in range(0, n), 别忘了 + 1

 

 1 #include <vector>
 2 #include <list>
 3 #include <map>
 4 #include <set>
 5 #include <deque>
 6 #include <stack>
 7 #include <bitset>
 8 #include <queue>
 9 #include <algorithm>
10 #include <functional>
11 #include <numeric>
12 #include <utility>
13 #include <sstream>
14 #include <iostream>
15 #include <iomanip>
16 #include <cstdio>
17 #include <cmath>
18 #include <cstdlib>
19 #include <ctime>
20 #include <string.h>
21 using namespace std;
22 #define N 60
23 int n;
24 int tree[N][N];
25 bool connect[N][N];
26 bool visit[N];
27 long long dp[N];
28 
29 void dfs(int v)
30 {
31     visit[v] = 1;
32     int i = 0, j = 0;
33     //cout << v << " : ";
34     for (i = 0; i < n; i++)
35     {
36         if (!connect[v][i] || visit[i]) continue;
37         tree[v][j++] = i;
38         //cout << i << " ";
39     }
40     //cout << endl;
41     for (i = 0; i < j; i++)
42     {
43         dfs(tree[v][i]);
44     }
45 }
46 
47 long long ans = 0;
48 long long f()
49 {
50     int i, j;
51     queue<int>q;
52     q.push(0);
53     vector<int>v;
54     while(!q.empty())
55     {
56         int tt = q.front();
57         v.push_back(tt);
58         q.pop();
59         for(i = 0; tree[tt][i] != -1; i++) q.push(tree[tt][i]);
60     }
61     for (i = v.size() - 1; i >= 0; i--)
62     {
63         int cnt = 0;
64         long long X = 1;
65         for (j = 0; tree[v[i]][j] != -1; j++)
66         {
67             cnt ++;
68             X *= (dp[tree[v[i]][j]] + 1);
69         }
70         if (cnt == 0) dp[v[i]] = 1;
71         else dp[v[i]] = X;
72     }
73     for (i = 0; i < n; i++)
74     {
75         ans += dp[i];
76         cout << i << "\t" << (int)dp[i] << endl;
77     }
78     return ans;
79 }
80 
81 class CentaurCompanyDiv2 {
82 public:
83     long long count(vector <int>, vector <int>);
84 };
85 
86 long long CentaurCompanyDiv2::count(vector <int> a, vector <int> b) {
87     n = a.size() + 1;
88     int i, j, k;
89     memset(tree, -1, sizeof(tree));
90     for (i = 0; i < a.size(); i++)
91     {
92         connect[a[i] - 1][b[i] - 1] = 1;
93         connect[b[i] - 1][a[i] - 1] = 1;
94     }
95     dfs(0);
96     f();
97     return ans + 1;
98 }

 

 DIV1 第一题, 注意T很大, 10**9, 暴力必定超时, 只能找规律了, 发现angle只能四个方向, 找到循环节(1,2,4)  再把没计算的 T - T % rotate 计算一下就好。

#include <iostream>
#include <string>
#include <string.h>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <math.h>
#include <stdio.h>
using namespace std;
int n;
int dir[4][2] = {1, 0, 0, -1, -1, 0, 0, 1};
long long x, y, angle;
vector<int>a;
long long myabs(long long T)
{
    if (T < 0) return -T;
    return T;
}
void f()
{
    int i;
    for (i = 0; i < a.size(); i++)
    {
        x += dir[angle][0] * a[i];
        y += dir[angle][1] * a[i];
        angle = (angle + a[i]) % 4;
    }
}
class RobotHerb
{
public:
    long long getdist(int T, vector <int> _a)
    {
        long long xx, yy;
        int i, j;
        a = _a;
        f();
        if (angle == 0)
        {
            xx = x * T;
            yy = y * T;
            return myabs(x) + myabs(y);
        }
        if (angle == 1)
        {
            x = 0; y = 0; angle = 0;
            for (i = 0; i < 4; i++)
            {
                for (j = 0; j < a.size(); j++)
                {
                    x += dir[angle][0] * a[j];
                    y += dir[angle][1] * a[j];
                    angle = (angle + a[j]) % 4;
                }
            }
            long long cnt = T / 4;
            xx = x * cnt;
            yy = y * cnt;
            for (i = 0; i < T % 4; i++)
            {
                for (j = 0; j < a.size(); j++)
                {
                    xx += dir[angle][0] * a[j];
                    yy += dir[angle][1] * a[j];
                    angle = (angle + a[j]) % 4;
                }
            }
            return myabs(xx) + myabs(yy);
        }
        if (angle == 2)
        {
            x = 0; y = 0; angle = 0;
            for (i = 0; i < 2; i++)
            {
                for (j = 0; j < a.size(); j++)
                {
                    x += dir[angle][0] * a[j];
                    y += dir[angle][1] * a[j];
                    angle = (angle + a[j]) % 4;
                }
            }
            long long cnt = T / 2;
            xx = x * cnt;
            yy = y * cnt;
            for (i = 0; i < T % 2; i++)
            {
                for (j = 0; j < a.size(); j++)
                {
                    xx += dir[angle][0] * a[j];
                    yy += dir[angle][1] * a[j];
                    angle = (angle + a[j]) % 4;
                }
            }
            return myabs(xx) + myabs(yy);
        }
        if (angle == 3)
        {
            x = 0; y = 0; angle = 0;
            for (i = 0; i < 4; i++)
            {
                for (j = 0; j < a.size(); j++)
                {
                    x += dir[angle][0] * a[j];
                    y += dir[angle][1] * a[j];
                    angle = (angle + a[j]) % 4;
                }
            }
            long long cnt = T / 4;
            xx = x * cnt;
            yy = y * cnt;
            for (i = 0; i < T % 4; i++)
            {
                for (j = 0; j < a.size(); j++)
                {
                    xx += dir[angle][0] * a[j];
                    yy += dir[angle][1] * a[j];
                    angle = (angle + a[j]) % 4;
                }
            }
            return myabs(xx) + myabs(yy);
        }
        return 0;
    }
};
int main()
{
    return 0;
}

 

转载于:https://www.cnblogs.com/kaitian521/archive/2013/04/30/Topcoder_SRM_570.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值