代码改变世界

srm 543 div1

2012-05-21 00:25  macaroniz  阅读(229)  评论(0)    收藏  举报

250pt

最开始想一位一位的单独求,但是发现计算每一位的0和1很复杂,需要按位dp。

于是想别的方法,注意到如果记SXOR(x)表示0到x的异或和,那么原问题可以转化为SXOR(R)^SXOR(L-1)。

如何快速的求出SXOR(X)呢?

方法有很多,我使用的是按位求。

注意到一个重要的性质:SXOR(2^n-1) = 0,n >= 2。

设X的二进制表示最高位为2^t,因此SXOR(X) =((X - 2^t + 1) % 2 ? 2^t : 0) + SXOR(X - 2^t)

需要对x = 0,1,2,3特判一下就可以了。

class EllysXors
{
public:
    long long calc(long long x)
    {
        if(x == 3) return 0;
        if(x == 2) return 3;
        if(x == 1) return 1;
        if(x == 0) return 0;
        long long gao = 0;
        for(gao = 1;gao*2 <= x;gao = gao*2);
        long long tmp = 0;
        if((x - gao + 1) % 2 == 1) tmp = gao;
        return tmp + calc(x - gao);
    }

    long long getXor(long long L, long long R)
    {
        if(L == R) return L;
        return calc(L-1) xor calc(R);
    }
};

500pt

这道题很容易看出状态转移方程,但是朴素的转移代价太大。

切入点在于要看出每个阶段都是凸单调的,并且转移不会出现交叉,即不会出现dp[a] 推出 dp[d],dp[b] 推出 dp[c],a < b,c < d这样的情况。

double dp[51][100100];
class EllysRivers
{
public:double sqr(int x)
{
    return 1.0*x*x;
}
double calc_time(int width,int speed,int height)
{
    return sqrt(sqr(width)+sqr(height))/speed;
}
double getMin(int length, int walk, vector <int> width, vector <int> speed)
{

    double walk_time = 1.0 / walk;
    int n = speed.size()+1;
    memset(dp,0,sizeof dp);

    for(int i = 1;i <= length;i++)
        dp[0][i] = dp[0][i-1] + walk_time;

    for(int i = 1;i < n;i++)
    {
        int last = 0;
        for(int j = 0;j <= length;j++)
        {
            int lastT = last;
            dp[i][j] = dp[i-1][last] + calc_time(width[i-1],speed[i-1],j - last);
            for(int k = last+1;k <= j;k++)
            {
                if(dp[i][j] >= dp[i-1][k] + calc_time(width[i-1],speed[i-1],j - k))
                {
                    dp[i][j] = dp[i-1][k] + calc_time(width[i-1],speed[i-1],j - k);
                    lastT = k;
                }
                else break;
            }
            last = lastT;
        }
        for(int j = 1;j <= length;j++)
            dp[i][j] = min(dp[i][j],dp[i][j-1] + walk_time);
    }
    //printf("%lf\n",dp[1][4]);
    return dp[n-1][length];
}

1000pt