2012icpc天津个人题解

本文深入探讨了竞赛编程中各类问题的解决策略,包括动态规划、贪心算法及数学建模等核心方法,并提供了具体实现代码示例。

H 签到概率题 推公式输入输出

B 求因子+进制转换 没什么难点 认真写就好

A 麻将胡牌..可怕的模拟

 

C wa了无数发的dp...结果基本思路就错了而且不知道错在哪...

E 数学知识 贪心+判连通 比较新奇..

 

F 后缀自动机...很正经的难题

K 复杂数据结构 splay伸展树

I 数学解复杂方程+最小区间覆盖...

 

这场层次不错 铜金之间尤其好 6题全是金5题是全银..题目也比较正

 

C dp又错..好像是后效性的锅..还没想太明白..这种时限比其他题长的 复杂度肯定不会太小O(n)注定会wa..

正解是常数小的50*O(n*10^4) 算下来是常数小的5亿了...

 

这个e就很有趣...虽然是数学(等比数列求和)+贪心+判连通 但并没有什么算法...

贪心就是for循环

判连通时 对于有加油站的点 如果它离最近的加油站距离超过d 则不连通(注意只有一个加油站的情况) 对于没有加油站的点 如果它离最近的加油站距离超过d/2(不能走一个来回) 则不连通

总共for+if就能写完 而且没有什么神奇的操作 就是不好想到...

复杂度O(n^3) 显然不是卡时间的题

代码:

#include<cstdio>

#include<algorithm>

#include<cmath>

using namespace std;

int mp[133][133], n, d, po[133][2], a[133];

int fx(int x, int y, int xx, int yy)

{

    return ceil(sqrt((xx - x)*(xx - x) + (yy - y)*(yy - y)));

}

int ok()

{

    int mm, i, j, f;

    for (i = 0; i < n; i++)

        if (a[i] == 1)

        {

            for (j = f = 0, mm = 1 << 28; j < n; j++)

                if (j != i&& a[j] == 1)

                    mm = min(mm, mp[i][j]), f = 1;

            if (f&&mm > d)  return 0;

        }

        else

        {

            for (j = 0, mm = 1 << 28; j < n; j++)

                if (a[j] == 1) mm = min(mm, mp[i][j]);

            if (mm > d / 2)  return 0;

        }

    return 1;

}

int main()

{

    int i, j, mm;

    while (~scanf("%d%d", &n, &d))

    {

        for (i = 0; i < n; i++)

            scanf("%d%d", po[i], po[i] + 1), a[i] = 1;

        for (i = 0; i < n; i++)

            for (j = i + 1; j < n; j++)

                mp[i][j] = mp[j][i] = fx(po[i][0], po[i][1], po[j][0], po[j][1]);

        for (i = 0; i < n; i++)

        {

            for (j = 0, mm = 1 << 28; j < n; j++)

                if (j != i) mm = min(mm, mp[i][j]);

            if (mm > d) { puts("-1"); break; }

        }

        if (i != n) continue;

        for (i = n - 1; i > 0; i--)

        {

            a[i] = 0;

            if (ok() == 0) a[i] = 1;

        }

        i = n - 1;

        while (!a[i]) i--;

        for (; i >= 0; i--)

            printf("%d", a[i]);

        puts("");

    }

}

 

C 动态规划总是给出正解能知道正解是对的 但想不到自己为什么错的...

不过这题正解的思路竟然意外简单 依次枚举所有转的可能 从左向右的话 固定1格 它左边的格该次转的次数总是非递增的 复杂度刚刚好

代码:

#include<cstdio> 

#include<cstring> 

#include<algorithm> 

using namespace std;

int dp[1005][13][13], n, i, j, p, q, k, tmp;

char a[1005], b[1005];

int main()

{

    while (~scanf("%s%s", a, b))

    {

        memset(dp, 63, sizeof(dp));//初始化为一个很大的数(不是63)

        dp[0][0][0] = 0, n = strlen(a);

        //dp[i][j][k]表示前i位相同且第i+1位增加为j ,i+2位增加为k的时对应的最小转动次数

        for (i = 0; i < n; i++)

            for (j = 0; j < 10; j++)

                for (k = 0; k < 10; k++)

                {

                    tmp = (b[i] - a[i] - j + 20) % 10;

                    //达到j时需要向上转的次数 +20为了保证括号内是正数

                    for (p = 0; p <= tmp; p++)

                        for (q = 0; q <= p; q++)

                            dp[i + 1][(k + p) % 10][q] = min(dp[i + 1][(k + p) % 10][q], dp[i][j][k] + tmp);

                    //p q分别是i+1,i+2转的次数 i+2的次数小于等于i+1

                    tmp = 10 - tmp;//向下

                    for (p = 0; p <= tmp; p++)

                        for (q = 0; q <= p; q++)

                            dp[i + 1][((k - p) % 10 + 10) % 10][(10 - q) % 10] = min(dp[i + 1][((k - p) % 10 + 10) % 10][(10 - q) % 10], dp[i][j][k] + tmp);

                }

        printf("%d\n", dp[n][0][0]);

    }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值