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;
}