• Codeforces 380 简要题解


    ABC见上一篇

     感觉这场比赛很有数学气息。

    D:

      显然必须要贴着之前的人坐下。

      首先考虑没有限制的方案数。就是2n - 1(我们把1固定,其他的都只有两种方案,放完后长度为n)

      我们发现对于一个限制,比它小的限制只有可能在它的一边。

      于是对于有限制的一段,我们可以找到最靠近边界的两个限制,取其中最大的限制,递归计算向比它小的限制的方向走它的限制步所覆盖的一段,这一段应该包含目前区间内所有的限制,剩下的就是没有限制的,可以直接计算。

    mycode:

    /* 
     * Problem: Sereja and Cinema
     * Author: Shun Yao
     */
    
    #include <string.h>
    #include <stdlib.h>
    #include <limits.h>
    #include <assert.h>
    #include <stdio.h>
    #include <ctype.h>
    #include <math.h>
    #include <time.h>
    
    #include <map>
    #include <set>
    #include <list>
    #include <stack>
    #include <queue>
    #include <deque>
    #include <string>
    #include <vector>
    #include <bitset>
    #include <utility>
    #include <iomanip>
    #include <numeric>
    #include <sstream>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    
    //using namespace std;
    
    const int MAXN = 100010, MOD = 1000000007LL;
    
    int n, a[MAXN], sum[MAXN];
    long long inv[MAXN], f[MAXN], finv[MAXN];
    
    long long comb(int x, int y) {
    	return f[x + y] * finv[x] % MOD * finv[y] % MOD;
    }
    
    long long func(int l, int r) {
    	long long ans;
    	if (sum[l - 1] == sum[r]) {
    		ans = 1;
    		int i;
    		for (i = l; i < r; ++i)
    			ans = (ans << 1) % MOD;
    		return ans;
    	}
    	int p, q;
    	for (p = l; p <= r; ++p)
    		if (a[p])
    			break;
    	for (q = r; q >= l; --q)
    		if (a[q])
    			break;
    	if (p == q && a[p] == 1)
    		return comb(p - l, r - p);
    	ans = 0;
    	int x, y;
    	if (a[p] >= a[q]) {
    		x = p;
    		y = x + a[p] - 1;
    		if (y >= q && y <= r)
    			ans += func(x + 1, y) * comb(x - l, r - y);
    	}
    	if (a[p] <= a[q]) {
    		y = q;
    		x = y - a[q] + 1;
    		if (x >= l  && x <= p)
    			ans += func(x, y - 1) * comb(x - l, r - y);
    	}
    	return ans % MOD;
    }
    
    int main(/*int argc, char **argv*/) {
    	int i;
    	
    	scanf("%d", &n);
    	sum[0] = 0;
    	for (i = 1; i <= n; ++i) {
    		scanf("%d", &a[i]);
    		sum[i] = sum[i - 1] + (a[i] != 0);
    	}
    	inv[1] = 1;
    	for (i = 2; i < MAXN; ++i)
    		inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD;
    	f[0] = finv[0] = 1;
    	for (i = 1; i < MAXN; ++i) {
    		f[i] = f[i - 1] * i % MOD;
    		finv[i] = finv[i - 1] * inv[i] % MOD;
    	}
    	printf("%I64d", func(1, n));
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

     E:

      这个题目我们可以发现实际上就是取一个区间的数集{a[i]},所求就是:1/2 * a[1] + 1/4 * a[2] + 1/8 * a[3] + ……,由于精度所以我们可以忽视a[50]以后的。

      我们可以考虑一个数为结果带来的代价。我们考虑比V大的数,Let the position of elements on the left: p1> p2> ... > Ps1. And positions right: q1 < q2 < ... < qs2.这样它带来的代价就是

      mycode:

    /* 
     * Problem: Sereja and Dividing
     * Author: Shun Yao
     */
    
    #include <string.h>
    #include <stdlib.h>
    #include <limits.h>
    #include <assert.h>
    #include <stdio.h>
    #include <ctype.h>
    #include <math.h>
    #include <time.h>
    
    #include <map>
    #include <set>
    #include <list>
    #include <stack>
    #include <queue>
    #include <deque>
    #include <string>
    #include <vector>
    #include <bitset>
    #include <utility>
    #include <iomanip>
    #include <numeric>
    #include <sstream>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    
    //using namespace std;
    
    const int MAXN = 300010;
    
    int n, a[MAXN];
    std::vector<std::pair<int, int> > v;
    std::set<int> s;
    
    double solve(int x) {
        double two, c1, c2;
        int cnt, prev, y;
        s.insert(x);
        std::set<int>::iterator it = s.find(x);
        two = 1.0;
        cnt = 0;
        prev = x;
        c1 = 0.0;
        while (cnt < 50) {
            y = *(--it);
            c1 += (prev - y) * two;
            if (y == 0)
                break;
            ++cnt;
            two /= 2.0;
            prev = y;
        }
        it = s.find(x);
        two = 1.0;
        cnt = 0;
        prev = x;
        c2 = 0.0;
        while (cnt < 50) {
            y = *(++it);
            c2 += (y - prev) * two;
            if (y == n + 1)
                break;
            ++cnt;
            two /= 2.0;
            prev = y;
        }
        return c1 * c2;
    }
    
    int main(/*int argc, char **argv*/) {
        int i;
        double ans;
        
        scanf("%d", &n);
        for (i = 1; i <= n; ++i)
            scanf("%d", a + i);
        for (i = 1; i <= n; ++i)
            v.push_back(std::make_pair(-a[i], i));
        std::sort(v.begin(), v.end());
        s.insert(0);
        s.insert(n + 1);
        ans = 0.0;
        for (i = 0; i < n; ++i)
            ans += solve(v[i].second) * a[v[i].second];
        printf("%.9lf", ans / 2.0 / n / n);
        
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
    
  • 相关阅读:
    spring mvc技术
    转 easyUI的iframe子页面操作父页面元素
    DG
    SqlServer数据库分离附加操作
    SqlServer2008系统数据库的作用和特点
    Oracle基础学习记录1.0
    聚集索引与非聚集索引
    苹果官方 Crash文件分析方法 (iOS系统Crash文件分析方法)
    iOS Crash文件的解析
    在同一台电脑上使用两个github账户
  • 原文地址:https://www.cnblogs.com/hsuppr/p/3518053.html
Copyright © 2020-2023  润新知