2019 蓝桥杯省赛 A 组模拟赛(一)-忽明忽暗

走廊里有 nn 盏灯,编号依次为 1,2,3,...,n,由学校电路控制中心管理。初始时,所有灯都是关闭的。某黑客入侵了学校电路控制中心,黑客想让灯忽明忽暗,进行了 n 轮操作。第 轮操作,会让所有编号为 ii 的倍数的灯状态反转,也就是打开的变为关闭,关闭的变为打开。现在黑客想知道,n 轮操作后,所有亮着的灯的编号之和为多少。因为答案很大,只需输出答案对 10^9+7 取模的结果。

输入格式

一个整数 n,表示灯的个数。

输出格式

一个整数,表示亮着的灯的编号之和对 10^9+7 取模的结果。

数据范围

对于 30% 的数据: 1n≤10^6

对于 60% 的数据:1n10^14。

对于 100% 的数据:1n10^18。

样例输入

20

样例输出

30
题解:

每个灯状态改变都是因为因数,所以最后灯是亮着还是熄灭取决于因数个数的奇偶性,但是一看数据范围10^18,有点蒙,看了讲解之后,才知道因数个数是奇数的数都是完全平方数,而完全平方数的和有公式n*(n+1)*(2*n+1)/6,然后在算的时候取一下模就行了。计算的时候也有技巧,因为除法不遵循同余,还要想办法把除六算出来,方法就是将6拆成2*3,t*(t+1)必然是2的倍数,直接除2就好,在判断t*(t+1)是不是3的倍数,除以3,不是则可以说明2*t+1肯定是3的倍数,因为t和t+1都不是3的倍数,那么只能是t%3=1,(t+1)%3=2,所以2*t+1是3的倍数。
转载自:https://blog.csdn.net/Goodbye_/article/details/86742923

本来想以如下的方法,对亮着的灯直接进行统计的,但是只能过几组数据,所以借鉴了别人的博客,获得了更高效的解决办法:

#include <algorithm>
#include <cmath>
#include <iostream>
using namespace std;
bool a[1000005];
int main() {
    long long n, mod = 1e9 + 7;
    cin >> n;
    long long ans = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = i; j <= n; j += i) {
            a[j] = !a[j];
        }
    }
    for (int i = 1; i <= n; i++) {
        if (a[i]) ans += i;
    }
    cout << ans % mod << endl;
    cout << sqrt(5) << endl;
    return 0;
}

更高效的办法:

代码:
#include<bits/stdc++.h>
using namespace std;
const long long  mod=1e9+7;
long long ans,n;
int main()
{
    scanf("%lld",&n);
    long long t=sqrt(n);
    ans=t*(t+1)/2;
    if(ans%3==0)
    ans=(ans/3)%mod*(2*t+1)%mod;
    else
    ans=(ans%mod*((2*t+1)/3)%mod)%mod;
    cout<<ans<<endl; 
    return 0;
}
posted @ 2019-03-29 21:59  里昂静  阅读(357)  评论(0编辑  收藏  举报