今天心情好,刷了两到ACM水题,思路很简单都在注释里,所以直接贴代码:

/**
 * @file 龟兔赛跑.cpp
 * @brief 龟兔赛跑 AC代码 (DP)
 * DP方程式: [到第i的充电站的最短时间] = [到最后一个冲了电的充电站的最短时间] + [那个充电站到第i个充电站的时间]
 *
 * @link http://acm.hdu.edu.cn/showproblem.php?pid=2059
 * @version 1.0
 * @author OWenT
 * @date 2013.07.15
 *
 * @history
 *
 *
 */

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <set>
#include <numeric>

int pn[128];
double dp[128]; /** dp[i] 表示 到第i个充电站的最小时间(0为开始位置,n+1为终点) **/

double calc_charge_time(int dis, int v1, int v2, int c) {
    if (dis <= c)
        return 1.0 * dis / v1;

    return 1.0 * c / v1 + 1.0 * (dis - c) / v2;
}

int main(int argc, char* argv[]) {
    using namespace std;

    double eps = std::numeric_limits<double>::epsilon();
    int l, n, c, t, vr, v1, v2;

    while(cin>> l) {
        cin >> n>> c>> t>> vr>> v1>> v2;

        pn[0] = 0; /** 0为起点 **/
        for (int i = 1; i <= n; ++ i) {
            cin>> pn[i];
        }
        pn[n + 1] = l; /** n+1为终点 **/

        memset(dp, 0, sizeof(dp));
        for(int i = 0; i <= n + 1; ++ i) {
            dp[i] = calc_charge_time(pn[i] - pn[0], v1, v2, c);
        }

        for(int i = 1; i <= n + 1; ++ i) {
            for(int j = 0; j < i; ++ j) {
                double tc = calc_charge_time(pn[i] - pn[j], v1, v2, c) + t + dp[j];
                dp[i] = std::min(tc, dp[i]);
            }
            
        }

        double rt = 1.0 * l / vr, tt = dp[n + 1];

        if (tt < rt)
            puts("What a pity rabbit!");
        else
            puts("Good job,rabbit!");
    }

    return 0;
}

/**
 * @file Zipper.cpp
 * @brief Zipper AC代码 (DP)
 * @link http://poj.org/problem?id=2192
 * DP方程式: [A串消耗个数i][B串消耗个数j] = min{[A串消耗个数i - 1][B串消耗个数j]|[A串消耗个数i][B串消耗个数j + 1]}
 * 以上分支选取条件是 A或B的新选用字符和C串新字符匹配
 *
 * @version 1.0
 * @author OWenT
 * @date 2013.07.15
 *
 * @history
 *
 *
 */

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <numeric>


char strA[256], strB[256], strC[512];
int dp[256][256]; /** dp[i][j] = k 表示A消耗了i个字符,B消耗了j个字符,拼成的C串消耗了k个字符(其实就是i+j) **/

int main(int argc, char* argv[]) {
    using namespace std;
    int s, n;

    scanf("%d", &n);
    for( s = 0; s < n; ++ s) {
        scanf("%s %s %s", strA, strB, strC);
        int lenA = strlen(strA);
        int lenB = strlen(strB);
        int lenC = strlen(strC);
        bool bFlag = false;

        if ( lenC != lenA + lenB ) {
            printf("Data set %d: no\n", s + 1);
            continue;
        }

        memset(dp, 0, sizeof(dp));

        if (strA[0] == strC[0])
            dp[1][0] = 1;
        if (strB[0] == strC[0])
            dp[0][1] = 1;

        for (int i = 0; i <= lenA; ++ i) {
            for (int j = 0; j <= lenB; ++ j) {
                if (0 == dp[i][j])
                    continue;

                int ri = i + 1, rj = j + 1;

                if (strA[i] == strC[dp[i][j]]) {
                    dp[ri][j] = dp[i][j] + 1;
                    if (ri + j == lenC)
                        bFlag = true;
                }

                if (strB[j] == strC[dp[i][j]]) {
                    dp[i][rj] = dp[i][j] + 1;
                    if (i + rj == lenC)
                        bFlag = true;
                }
            }
        }

        printf("Data set %d: %s\n", s + 1, bFlag? "yes": "no");
    }

    return 0;
}

题目链接:http://acm.pku.edu.cn/JudgeOnline/problem?id=1986

这是一道并查集+树的题,采用Tarjan离线算法

首先BS一下出题的人,也太懒了吧,还要我们看1984题才知道输入

题目的意思是告诉一个节点数为40000的树,问我们两个节点间的距离。实际上就是找出公共父节点,Tarjan算法写挫了很容易TLE,我开始用Vector就写搓了,结果TLE,后来重写,自己写邻接表然后AC了。

这道题是我专门为了了解和学习树状数组而写的

这题用树状数组记录翻转次数,然后mod一个2,也可以不断地取反

还要用到二维的树状数组.于是我专门写了个模板用

题目链接:http://acm.pku.edu.cn/JudgeOnline/problem?id=1720

这题纯计算几何就搞定了,开始我写了个很长很长的代码,但是Wa掉,也不知道是代码那里有疏漏还是精度问题

题目链接:http://acm.pku.edu.cn/JudgeOnline/problem?id=3631

我讨厌这么长的题目

这题是模拟那个Hash算法,有点像我之前转载的那篇文章里提到的Hash

打造最快的Hash表(转) [以暴雪的游戏的Hash为例] 这里是用两个Hash函数算出两个Hash值h1和h2,如果h1位置已经被占用就检查h2位置,如果都被占用就把原来的替换掉再给原来的字符串重新计算映射。这样下去可能出现死循环。会出现死循环就输出

为什么我用线段数这么不灵活呢?

大概思路是线段数记录某牛之前的坐标小于这个牛的牛的坐标和和牛的个数

然后其他部分线性数组记录

OK,贴代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define MAXN 20005
class cow
{
public:
    int v;
    int pos;
    cow(){};
    ~cow(){};
};

bool cmp(cow a,cow b)
{
    return a.v < b.v;
}
cow cw[MAXN];
long long belowXNT[MAXN];//树状数组,保存小于等于某坐标的牛的个数,计算时使用
long long belowXN[MAXN];//一般数组,保存小于等于某坐标和索引的牛的个数
long long velowXRT[MAXN];//树状数组,保存索引小于等于某的牛且坐标也小于它的牛的坐标之和,计算时使用
long long velowXR[MAXN];//一般数组,保存索引小于等于某的牛且坐标也小于它的牛的坐标之和
long long velowXRA[MAXN];//一般数组,保存小于等于某牛的坐标之和

int lowbit(int t)
{
    return t&(t^(t-1));
}
void setVal(int pos, int num, long long treeG[], int maxn)
{
    while (pos <= maxn)
    {
        treeG[pos] += num;
        pos += lowbit(pos);
    }
}
long long getSum(int pos, long long treeG[])
{
    long long sum = 0;
    while (pos > 0)
    {
        sum += treeG[pos];
        pos -= lowbit(pos);
    }
    return sum;
}



int main()
{
    int i,n;
    long long output = 0;
    memset(belowXN, 0, sizeof(belowXN));
    memset(belowXNT, 0, sizeof(belowXN));
    memset(velowXR, 0, sizeof(velowXR));
    memset(velowXRA, 0, sizeof(velowXRA));
    memset(velowXRT, 0, sizeof(velowXRT));
    scanf("%d",&n);
    for(i = 0 ; i < n ; i ++)
        scanf("%d %d", &cw[i].v, &cw[i].pos);

    sort(cw, cw + n, cmp);
    for(i = 0 ; i < n ; i ++)
    {
        velowXRA[i] = velowXRA[i - 1] + cw[i].pos;
        setVal(cw[i].pos, 1, belowXNT, MAXN);
        setVal(cw[i].pos, cw[i].pos, velowXRT, MAXN);
        velowXR[i] = getSum(cw[i].pos, velowXRT);
        belowXN[i] = getSum(cw[i].pos, belowXNT);
    }

    for(i = 1 ; i < n ; i ++)
        //output += cw[i].v * ((belowXN[i] - 1) * cw[i].pos - velowXR[i] + cw[i].pos + velowXRA[i] - velowXR[i] - (i - belowXN[i] + 1) * cw[i].pos);
        output += cw[i].v * ((belowXN[i] - i + belowXN[i] - 1 ) * cw[i].pos - 2 * velowXR[i] + velowXRA[i]);//这里是上面式子的简化版

    printf("%lld\n",output);
    return 0;
}