SRM 543

div1 250

令f[X] = 1^2^3^......^X;

找规律发现X= 1, 2, ... 20. The sequence is {1, 3, 0, 4, 1, 7, 0, 8, 1, 11, 0, 12, 1, 15, 0, 16, 1, 19, 0, 20}

Can you see it?If X mod 4 == 0, then X. If X mod 4 == 1 then 1. If X mod 4 == 2 then X+1. If X mod 4 == 3 then 0.

然后秒过:

public class EllysXors
{
	long xor1N(long N)
	{
		if (N % 4 == 0) return N;
		if (N % 4 == 1) return 1;
		if (N % 4 == 2) return N + 1;
		return 0;
	}
	
	public long getXor(long L, long R)
	{
		return xor1N(R) ^ xor1N(L - 1);
	}
};

div2 1000

递归三次+三分,详见代码

int a[3][2];
int w;
double dfs(int id, double len)
{
    if(id>=3)return len/(double)w;
    double l = 0.0, r = len;
    double ans = 200000000.0;
    for(int i = 0; i < 100; i++)
    {
        double m1=l+(r-l)/3.0;
        double m2=r-(r-l)/3.0;
        double a1 = dfs(id+1, len-m1)+sqrt(a[id][0]*a[id][0]+m1*m1)/a[id][1];
        ans = min(ans, a1);
        double a2 = dfs(id+1, len-m2)+sqrt(a[id][0]*a[id][0]+m2*m2)/a[id][1];
        ans = min(ans, a2);
        if(a1<a2)r = m2;
        else l=m1;
    }
    return ans;
}

double EllysThreeRivers::getMin(int length, int walk, vector <int> width, vector <int> swim) {
	for(int i = 0; i < 3; i++)
	{
	    a[i][0]=width[i];
	    a[i][1]=swim[i];
	}
	w = walk;
	return dfs(0, length);
}

div1 550

DP

f[i][j]表示在第 i 个岛的 j 高度处花费的最少时间

需要注意的是状态数有50*100000,所以状态转移必须在O(1)的时间内解决

1.要转移到i+1岛上的j位置,i岛上的位置从0到max一定是一个凹函数,并设i岛上的这个凹点为k位置;

2.要转移到i+1岛上的j+1位置,i岛上的位置一定是从k开始找;

关于1的证明:

我们知道f[i][k+1] > f[i][k] > f[i][k-1]

并且 k+1 -> j < k -> j < k-1 -> j

所以必然存在一个k使得f[i][k]+(k -> j)<f[i][k+1]+(k+1 -> j)且f[i][k]+(k -> j)<f[i][k-1]+(k-1 -> j);(所以是凹函数)


关于2的证明:

因为 f[i-1][k]+ad < f[i-1][k-1]+bd;

假设从k-1出发到J+1比从k出发更优,

即:f[i-1][k-1]+bc<f[i-1][k]+ac;

联立上面两式可得:ad+bc<bd+ac;

又因为ao+oc>ac

           bo+od>bd

联立可得ad+bc>bd+ac

矛盾,所以假设不成立,所以从k出发到J+1更优!

证毕。


class EllysRivers {
public:
	double getMin(int, int, vector <int>, vector <int>);
};

double f[55][100010];
double EllysRivers::getMin(int length, int walk, vector <int> width, vector <int> speed) {
	int n = width.size();
	memset(f,0,sizeof(f));
	for(int i = 0; i <= length; i++)f[0][i]=(double)i/(double)walk;
	for(int i = 0; i < n; i++)
	{
	    int k = 0;
	    for(int j = 0; j <= length; j++)
	    {

	        while(k<length&&f[i][k]+sqrt((double)(j-k)*(j-k)+(double)width[i]*width[i])/(double)speed[i]>
                        f[i][k+1]+sqrt((double)(j-k-1)*(j-k-1)+(double)width[i]*width[i])/(double)speed[i])
            {
                    k++;
            }
            f[i+1][j]=f[i][k]+sqrt((double)(j-k)*(j-k)+(double)width[i]*width[i])/(double)speed[i];
	    }       //(j-k)*(j-k)可能会超int
	}
	return f[n][length];
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值