• 2019洛谷csp冲刺模拟赛


    难题做不动就去翻去年的洛谷csp题做,实在是水啊~

    第一次

    (A)

    (dp_{i, j})表示使用(i)个色子得到点数为(j)的概率,这样求出(dp_x)(dp_y)两个(dp)数组后就可以枚举(x)个色子得到的点数,(y)个色子得到的点数是一个前缀,枚举即可。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    
    int x, y;
    
    double dp[1050][6050], sum[6050];
    
    int main()
    {
    	scanf("%d%d", &x, &y);
    	for (int i = 1; i <= 6; i++) dp[1][i] = 1.0 / 6.0;
    	for (int i = 1; i <= (max(x, y)) - 1; i++)
    		for (int j = 1; j <= 6 * i; j++)
    			for (int k = 1; k <= 6; k++)
    				dp[i + 1][j + k] = dp[i + 1][j + k] + dp[i][j] / 6.0;
    	double ans = 0, sum = 0;
    	for (int i = 0; i <= x * 6; i++)
    		ans += sum * dp[x][i], sum += dp[y][i];
    	printf("%.2lf", ans * 100.0); putchar('%');
    	return 0;
    }
    

    (B)

    显然最后每个人都会到某个人站的地方集合。

    那么先按每个人站的地方排序,从左往右枚举集合的位置,发现这个位置之前的人距离会增加,之后的人的距离会减少,转移是(O(1))的。

    所以瓶颈在于排序,时间复杂度(O(n))

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    
    using namespace std;
    
    #define ll long long
    
    const int N = 1000000;
    const ll INF = 999999999999999999;
    
    int a[N + 50], b[N + 50], n;
    
    ll sumb[N + 50], sufb[N + 50];
    
    struct Node
    {
    	int a, b;
    } dl[N + 50];
    
    void Read(int &x)
    {
    	x = 0; int p = 0; char st = getchar();
    	while (st < '0' || st > '9') p = (st == '-'), st = getchar();
    	while (st >= '0' && st <= '9') x = (x << 1) + (x << 3) + st - '0', st = getchar();
    	x = p ? -x : x;
    	return;
    }
    
    ll Abs(ll x)
    {
    	return x < 0 ? -x : x;
    }
    
    int Cmp(Node a, Node b)
    {
    	return a.a < b.a;
    }
    
    int main()
    {
    	Read(n);
    	for (int i = 1; i <= n; i++) Read(dl[i].a);
    	for (int i = 1; i <= n; i++) Read(dl[i].b);
    	ll ans = INF, tmp = 0;
    	sort(dl + 1, dl + n + 1, Cmp);
    	for (int i = 1; i <= n; i++) sumb[i] = sumb[i - 1] + dl[i].b;
    	for (int i = n; i >= 1; i--) sufb[i] = sufb[i + 1] + dl[i].b;
    	for (int i = 1; i <= n; i++) tmp = tmp + 1LL * Abs(dl[i].a - dl[1].a) * dl[i].b;
    	ans = tmp; 
    	for (int i = 2; i <= n; i++)
    	{
    		tmp = tmp + 1LL * sumb[i - 1] * Abs(dl[i].a - dl[i - 1].a) - 1LL * sufb[i] * Abs(dl[i].a - dl[i - 1].a);
    		ans = min(ans, tmp);
    	}
    	printf("%lld", ans);
    	return 0;
    }
    

    (C)

    对于一段函数,最大值最小值已知的情况下将这段函数拟合到(min + (max - min) / 2)是最优的。

    所以问题转化为将数列分成一些段使得每段的极差尽可能小。

    二分最小极差判断可行性。

    发现判断可行性可以用倍增实现,注意这里倍增时不能算出总共需要的段数,而是段数大于给定段数就要退出。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <cmath>
    
    using namespace std;
    
    const int N = 1000000; 
    
    int n, x[N + 50], y[N + 50], stmin[25][N + 50], stmax[25][N + 50], maxx;
    
    void Read(int &x)
    {
    	x = 0; int p = 0; char st = getchar();
    	while (st < '0' || st > '9') p = (st == '-'), st = getchar();
    	while (st >= '0' && st <= '9') x = (x << 1) + (x << 3) + st - '0', st = getchar();
    	x = p ? -x : x;
    	return;
    }
    
    void Prework()
    {
    	maxx = 21;
    	for (int j = 1; j <= maxx; j++)
    		for (int i = 1; i + (1 << j) - 1 <= n; i++)
    			stmin[j][i] = min(stmin[j - 1][i], stmin[j - 1][i + (1 << (j - 1))]),
    			stmax[j][i] = max(stmax[j - 1][i], stmax[j - 1][i + (1 << (j - 1))]);
    	return;
    }
    
    bool Check(int d, int m)
    {
    //	cout << d << endl;
    	int l = 1, i;
    	for (int i = 0; i < m && l <= n; i++)
    	{
    		int tmpmax = -1, tmpmin = 1000000001, r = l;
    		for (int j = maxx; j >= 0; j--)
    			if (r + (1 << j) - 1 <= n)
    				if (max(tmpmax, stmax[j][r]) - min(tmpmin, stmin[j][r]) <= d)
    					tmpmin = min(tmpmin, stmin[j][r]), tmpmax = max(tmpmax, stmax[j][r]), r += (1 << j);
    	//	cout << l - 1 << " " ;
    		l = r;
    	}
    //	cout << endl;
    	return l == n + 1;
    }
    
    void Print(int x)
    {
    	if (x > 9) Print(x / 10);
    	putchar(x % 10 + '0');
    	return;
    }
    
    int main()
    {
    	scanf("%d", &n);
    	for (int i = 1; i <= n; i++) scanf("%*d%d", &stmin[0][i]), stmax[0][i] = stmin[0][i];
    	Prework();
    	int t, m;
    	scanf("%d", &t);
    	while (t--)
    	{
    		scanf("%d", &m);
    		int l = 0, r = 1000000001;
    		while (l < r)
    		{
    			int mid = (l + r) >> 1;
    			if (Check(mid, m)) r = mid;
    			else l = mid + 1; 
    		}
            if (l % 2) printf("%d.5
    ", l/2);
            else printf("%d
    ", l/2);
    	}
    	return 0;
    }
    
  • 相关阅读:
    03-模板引擎
    C#扩展方法
    DataTable转IHashObjectList
    创建DataTable
    02-一般处理程序基础
    css3相关样式
    css样式
    css基础知识
    表单和HTML5
    表格相关知识
  • 原文地址:https://www.cnblogs.com/Tian-Xing-Sakura/p/13764747.html
Copyright © 2020-2023  润新知