2020 CCPC-Wannafly Winter Camp Day2 A C

A:求元音字母在子串中的长度占比的期望
字符串长度n,则子串的数目为(n*(n+1))/ 2
利用前缀和,使用数组sumn[i]来记录到第i位有多少个元音字母,利用前缀和就可以计算区间和。
例:2~6区间和 = sumn[6] - sumn[1]
在使用数组f[i]表示长度为i的子串共有多少个元音字母。
f[i+1] = f[i] + sumn[n-i+1] - sumn[i-1]
因为长度为i的子串一定是长度为i+1串的子串,所以可以递推,i+1串元音个数与i串个数的差值在于中间一个区间多加了一次。
故 sum += f[i]/i
计算期望即可

#include <iostream>
using namespace std;
long long i,cnt,sumn[1000009],a[1000009],n;
double sumnn;
string s;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> s;
    n = s.length();
    for(i = 0; i < s.length(); i ++ )
    {
        if(s[i] == 'a' || s[i] == 'e' || s[i] == 'i' || s[i] == 'o' || s[i] == 'u' || s[i] == 'y')
        {
            cnt ++;
        }
        sumn[i+1] = cnt;
    }
    a[1] = cnt;
    for(i = 2; i <= s.length(); i ++ )
    {
        a[i] = a[i-1] + sumn[s.length()-i+1] - sumn[i-1];
    }
    for(i = 1; i <= n; i ++ )
    {
        sumnn += (double)a[i]/(double)i;
    }
    printf("%.10lf",sumnn*2.0/(n*(n+1)));
}

C题 看出是尼姆博弈
因为在你先手取走之后,可以视为当下取过之后的石子,对手先手。即如果你取过之后的石子堆异或和为0,则对手必败,你必赢
即判断有多少堆石子y满足 y > x ^ y 其中x是前缀异或和。
x^y就是除去y的所有石子的异或和。y取走一部分后=x ^ y,异或和为0
因为 y > x ^ y,所以y的最高位一定高于或等于x的最高位,否则x的最高位不变,不满足
其次x ^ y,在x的最高位再高的部分都与y相同,只考虑x的位数,二进制第i位的值大于(<i)的部分和,所以只要x的最高位对应位y也为1即可。

#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + 50;
long long ans[65] = {0}; //数据范围2^60
//用于累加所有石子堆对应位的0/1
int main()
{
	int n;
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n;
	long long sum = 0;
	for(int i = 0; i < n; i++)
	{
		long long a;
		cin >> a;
		long long x = a;
		sum ^= a;//前缀异或和
		for(int j = 0; x != 0; j++)
		{
			ans[j] += x % 2;
			x /= 2;
		}
		long long t = sum, wei = 0;
		while(t)
		{
			t = t / 2;
			wei++;
		}
		cout << ans[wei - 1] << endl;
	}
	return 0;
}
发布了11 篇原创文章 · 获赞 0 · 访问量 629

猜你喜欢

转载自blog.csdn.net/weixin_43934344/article/details/104015008