2013 Pacific Northwest Region Programming Contest补题

A. Assignments

水题,随便写。

B. Bones’s Battery

二分油箱容积,判断是否符合。判断可行性时预处理各点两两间是否能一次走完,能的话在这两点间构建边权为1的边,完了后跑最短路得到最大加油次数,与k比较即可。

代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 const int maxn = 100 + 5;
 7 typedef long long ll;
 8 const ll inf = 0x3f3f3f3f;
 9 
10 ll mp[maxn][maxn];
11 int dp[maxn][maxn];
12 int n, m, K;
13 
14 void ini() {
15     for(int k=0;k<n;k++) {
16         for(int i=0;i<n;i++) {
17             mp[i][i] = 0;
18             for(int j=0;j<n;j++) {
19                 if(i==k || mp[i][k]==inf || mp[k][j]==inf) continue;
20                 mp[i][j] = min(mp[i][j], mp[i][k]+mp[k][j]);
21             }
22         }
23     }
24 }
25 
26 bool solve(ll x) {
27     for(int i=0;i<n;i++) {
28         for(int j=0;j<n;j++) 
29             dp[i][j] = mp[i][j]<=x?1:inf;
30     }
31     for(int k=0;k<n;k++) {
32         for(int i=0;i<n;i++) {
33             dp[i][i] = 0;
34             for(int j=0;j<n;j++) {
35                 if(i==k || dp[i][k]==inf||dp[k][j]==inf) continue;
36                 dp[i][j] = min(dp[i][j], dp[i][k]+dp[k][j]);
37             }
38         }
39     }
40     for(int i=0;i<n;i++) {
41         for(int j=0;j<n;j++) if(dp[i][j]>K) return 0;
42     }
43     return 1;
44 }
45 
46 int main() {
47     int T;
48     scanf("%d", &T);
49     while(T--) {
50         int x, y;
51         ll w, l=0, r=0;
52         scanf("%d%d%d", &n, &K, &m);
53         memset(mp, 0x3f, sizeof(mp));
54         for(int i=0;i<m;i++) {
55             scanf("%d%d%lld", &x, &y, &w);
56             mp[x][y] = mp[y][x] = w;
57             r+=w;
58         }
59         ini();
60         while(l<r) {
61             ll mid = l+r>>1;
62             if(solve(mid)) r=mid;
63             else l=mid+1;
64         }
65         printf("%lld\n", l);
66     }
67 }
View Code

C. Crusher’s Code

概率顺着走,概数倒着走,用dp[si]表示由si状态达到最终状态的平均步数,我们可以得到2个方程式:

第一种情况:

第二钟情况:

其中sj表示si能达到的状态,cnt表示共有多少个状态可达。

代码:

 1 #include<cstring>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<unordered_map>
 5 #include<iostream>
 6 using namespace std;
 7 const int maxn = 15;
 8 typedef double intd;
 9 
10 int a[maxn], b[maxn];
11 unordered_map<int,intd> dp[2];
12 
13 int n, ed;
14 
15 int Hash(int *arry) {
16     int rtn = 0;
17     for(int i=0;i<n;i++)    
18         rtn = rtn*8 + arry[i];
19     return rtn;
20 }
21 
22 intd Dp1() {
23     int sta = Hash(a);
24     if(sta == ed) return 0.0;
25     if(dp[0].count(sta)) return dp[0][sta];
26     intd sum = 0.0;
27     int cnt = 0;
28     for(int i=0;i<n;i++) {
29         for(int j=0;j<n;j++) if(a[min(i,j)]>a[max(i,j)]){
30             cnt ++;
31             swap(a[i], a[j]);
32             sum += Dp1();
33             swap(a[i], a[j]);
34         }
35     }
36     return dp[0][sta] = sum/(1.0*cnt) + n*n*1.0/(1.0*cnt);
37 }
38 
39 intd Dp2() {
40     int sta = Hash(a);
41     if(sta == ed) return 0.0;
42     if(dp[1].count(sta)) return dp[1][sta];
43     intd sum = 0.0;
44     int cnt = 0;
45     for(int i=0;i<n-1;i++) if(a[i]>a[i+1]){
46         cnt ++;
47         swap(a[i], a[i+1]);
48         sum += Dp2();
49         swap(a[i], a[i+1]);
50     }
51     return dp[1][sta] = sum/(1.0*cnt) + (n-1)*1.0/(1.0*cnt);
52 }
53 
54 int main() {
55     int T;
56     scanf("%d", &T);
57     while(T--) {
58         scanf("%d", &n);
59         for(int i=0;i<n;i++) {
60             scanf("%d", a+i);
61             b[i] = a[i];
62         }
63         sort(b, b+n);
64         for(int i=0;i<n;i++) {
65             int rk=lower_bound(b,b+n,a[i])-b;
66             a[i] = rk;
67         }
68         for(int i=0;i<n;i++)
69             b[i] = a[i];
70         sort(b, b+n);
71         int be = Hash(a);
72         ed = Hash(b);
73         dp[0].clear();
74         dp[1].clear();
75         Dp1();
76         Dp2();
77         printf("Monty %.6f Carlos %.6f\n", dp[0][be], dp[1][be]);
78     }
79     return 0;
80 }
View Code

D. Delta Quadrant

转换一下题意就知道这个题就是给定一棵树,删去k条边,保证其联通,求最小权值和,输出时乘上2即可。

随便取个点当作根节点,用dp[i][j]表示以节点i为根节点的字树中删去j条路径的最大权值,dfs遍历每个节点即可。

注意根节点可能会被删除,所以遍历时加个判断,如果某棵子树的节点树就为N-k就用它的权值和跟新答案。

代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 typedef long long ll;
 7 const int maxn = 1e4 + 5;
 8 const int maxm = 20 + 5;
 9 const ll inf = 0x3f3f3f3f3f3f;
10 
11 struct Node
12 {
13     int v, u, to;
14     ll w;
15 }p[maxn<<1];
16 int h[maxn];
17 int tot;
18 ll dp[maxn][maxm];
19 int N, k;
20 ll sum, ans;
21 
22 void ini()
23 {
24     tot = 0;
25     sum = 0;
26     memset(h, -1, sizeof(h));
27     memset(dp, 0, sizeof(dp));
28 }
29 
30 void add(int v,int u,ll w)
31 {
32     p[tot].v = v;
33     p[tot].u = u;
34     p[tot].w = w;
35     p[tot].to = h[v];
36     h[v] = tot++;
37 }
38 
39 void dfs(int v,int fa,int& cnt,ll& sw)
40 {
41     cnt = 1;
42     sw = 0;
43     for(int t=h[v];~t;t=p[t].to) {
44         int u = p[t].u;
45         if(u == fa) continue;
46         int cn;
47         ll sn;
48         dfs(u, v, cn, sn);
49         if(cn == N-k)
50             ans = min(ans, sn*2);
51 
52         if(cn <= k)
53             dp[u][cn] = dp[u][cn-1]+p[t].w;
54         sw += p[t].w + sn;
55         cnt += cn;
56         for(int i=k;i>=0;i--) {
57             ll maxs = 0;
58             for(int j=0;j<=i;j++)
59                 maxs = max(maxs, dp[v][j]+dp[u][i-j]);
60             dp[v][i] = maxs;
61         }
62     }
63 }
64 
65 int main()
66 {
67     int T;
68     scanf("%d", &T);
69     while(T--) {
70         ini();
71         scanf("%d%d", &N, &k);
72         for(int i=0;i<N-1;i++) {
73             int v, u;
74             ll w;
75             scanf("%d%d%lld", &v, &u, &w);
76             add(v, u, w);
77             add(u, v, w);
78             sum += w;
79         }
80         int cnt;
81         ll sn;
82         ans = inf;
83         dfs(0, 0, cnt, sn);
84         if(cnt==N-k) {
85             printf("%lld\n", sum*2);
86             continue;
87         }
88         for(int i=0;i<N;i++)
89             ans = min(ans, 2*sum-2*dp[i][k]);
90         printf("%lld\n", ans);
91     }
92     return 0;
93 }
View Code

 E. Enterprising Escape

水题,优先队列一下就行。

F.   Federation Favorites

水水水,暴力即可。

G. Generations of Tribbles

H2O,直接写。

H. Holodeck Hacking

可将X分解为:

那么Y可表示为:

我们可以知道 a[i] < 10,而Y的个位与a[i]+a[k-i]的个位是一定相同的,我们枚举a[i]+a[k-i]的大小(最多两种),减去第i项与k-i项,可以发现变成了一个类似的子问题,dfs即可,注意高位不能有前导0.

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 20;

ll pows[maxn];

void ini()
{
    pows[0] = 1;
    for(int i=1;i<maxn;i++)
        pows[i] = pows[i-1]*10;
}

ll dfs(ll n,int len,int flag)
{
    if(n == 0)
        return 1;
    if(n < 0)
        return 0;
    if(len == 0) return 0;
    if(len == 1) {
        if(n < 20 && (n & 1)==0) return 1;
        return 0;
    }

    ll rtn = 0;
    ll x = n%10;
    rtn += dfs((n-x*(1+pows[len-1]))/10, len-2, 0)*(x+1-flag);
    rtn += dfs((n-(10+x)*(1+pows[len-1]))/10, len-2, 0)*(9-x);

    return rtn;
}

int main()
{
    int T;
    ll n;
    ini();
    scanf("%d", &T);
    while(T--) {
        scanf("%lld", &n);
        int len = 0;
        ll m = n;
        while(m) len++, m/=10;
        ll ans = 0;
        for(int i=len;i>=1;i--)
            ans += dfs(n, i, 1);
        printf("%lld\n", ans);
    }
}
View Code

 

I. Interstellar Trade

想法题,想到了这个题就贼水了。

引入虫洞相当于把整个宇宙分为了两大块,使得两个宇宙间星球距离减小,但每个宇宙间的星球就没有受惠。这个题相当于把每个宇宙分为两部分,使得每部分星球最大距离最小。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 4000 + 5;

int a[maxn];

int main()
{
    int T;
    scanf("%d", &T);
    while(T--) {
        int n;
        scanf("%d", &n);
        for(int i=0;i<n;i++)
            scanf("%d", a+i);
        sort(a, a+n);
        int ans = 0;
        for(int i=0;i<n;i++)
            ans = max(ans, min(a[i]-a[0], a[n-1]-a[i]));
        printf("%d\n", ans);
    }
    return 0;
}
View Code

 

J. Janeway’s Journey

挖坑。

K. Klingon Warfare

挖坑。

L. Languages

水题,暴力匹配。

M. Mass Production

待补。

转载于:https://www.cnblogs.com/UtopioSPH001/p/9028182.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值