book
归档: OI 
flag
mode_edit

今天又是被吊打的一天呢

博弈

上午看了看19号的题,划了一波水,学习了一波博弈论

大概的思路就是。。两个人在玩♂游♂戏,希望通过一顿操作之后使得自己的尽量大,对手的尽量小

这种博弈是没有胜负的

我们不妨设两个人都是傻逼

然后给其中一个人充值智商,被充值智商的人肯定充满了智慧,他就会去套路没有智商的傻逼,于是我们就得到了一种策略

然后我们给第二个人也充值智商,这样他就不会被轻易套路了,他会根据对手的操作来是自己的损失尽量小

这样我们就得到了“双方都按最优策略行动”的方案

数论

下午有课,讲了数论和计算几何

雅礼的人很多,足足坐了一个大会议室

T1

给定$x,n$求

$$
f(x)=\sum_{i=1}^nx\ \text{mod} \ i
$$

其中$1\leq x,n\leq 10^9$

首先$O(n)$大暴力是不行的

那怎么搞啊。。

我们注意一下模运算的性质:

$$
f(x)=\sum_{i=1}^nx\ \text{mod} \ i=\
\sum_{i=1}^n(x-\lfloor\frac{x}{i}\rfloor\times i)=\
nx-\sum_{i=1}^n\lfloor\frac{x}{i}\rfloor\times i
$$

然后我们注意右半边的一些性质:$\lfloor\frac{x}{i}\rfloor$这个值,存在一段连续的$i$,使得这个值是不变的,如果我们可以预处理出来一共有几段,就可以等差数列求和辣

我们设$j = \lfloor\frac{x}{i}\rfloor$,$k$是满足$\lfloor\frac{x}{k}\rfloor=j$的最大整数,那么我们有$kj\leq x$,所以$k=\lfloor\frac{x}{j}\rfloor$

这样我们就搞出来了一段,用等差数列求和一下就好了

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll f(ll n, ll x)
{
    ll ans = n * x;
    ll now = 1, tmp = 0, ed = 0;
    while(now <= x)
    {
        tmp = x / now, ed = x / tmp;
        ans -= tmp * (ed + now) * (ed - now + 1) / 2;
        now = ed + 1;
    }
    return ans;
}
int main()
{
    ll n, x;
    cin >> n >> x;
    cout << f(n, x) << endl;
}

T2

原题地址:Luogu

我们考虑一下$f(x+1)$与$f(x)$的关系
$$
f(x+1)-f(x)=n-\sum_{i=1}^ni(\lfloor\frac{x+1}{i}\rfloor-\lfloor\frac{x}{i}\rfloor)
$$
考虑一些后面那一大串求和的意义

假如$i$不是x+1的约数,对$f(x+1)$的贡献会比对$f(x)$的贡献多$1$

否则对$f(x+1)$的贡献会比对$f(x)$的贡献少$i-1$

所以我们可以认为$f(x+1)-f(x)=n-(x+1的约数和)$

(其实可以自己打个表观察一下

然后用$O(n\log n)$时间预处理一下约数和

代码

//luogu P3708
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
typedef long long ll;
ll func(ll n, ll x)
{
    ll ans = n * x;
    ll now = 1, tmp = 0, ed = 0;
    while(now <= x)
    {
        tmp = x / now, ed = x / tmp;
        ans -= tmp * (ed + now) * (ed - now + 1) / 2;
        now = ed + 1;
    }
    return ans;
}
ll f[maxn], sum[maxn], n;
int main()
{
    cin >> n;
    for (int i = 1; i <= n; ++i)
        for (int j = i; j <= n; j += i)
            sum[j] += i;
    f[1] = func(n, 1);
    for (int i = 2; i <= n; ++i)
        f[i] = f[i - 1] + n - sum[i];
    for (int i = 1; i <= n; ++i)
        cout << f[i] << ' ';
    cout << endl; 
}

T3往后什么的。。真的不会啊。。。我太菜了。。。

navigate_before navigate_next