2017NOIP模拟赛-科普基地

今天回来打的第一场NOIP难度的试题,结果惨不忍睹。写一下每道题的做法,然后每道题犯的__弱智__错误
UPD:2018.9.15 突然这篇题解就变成很多大佬要看的了,因为之前是写给自己看的,所以写的很简略,这次修改一下第二道题的描述(第一题建议找其他AC的人看看,我的做法比较依赖STL,而且比较难读懂)

Moni

题意

每天 \(t\) 时刻将会有人取车或者放车,这个序列满足FIFO原则,每个人的时间代价是 \(delta(t)\)

\(q\) 次询问,每次问你如果在初始时刻投放 \(cnt\) 个车,总的代价是多少?

题目分析

看到这道题的时候第一想法是brute force,然后去拿个 \(60 pts\)

\(60 pts\) 做法:直接模拟计算每次出队的时候人的代价,加起来就行了。\(O(n * q)\)

花了15分钟写了个暴力,然后我们发现这个做法的问题是有很多次的计算是用的是之前使用过的,那么我们能不能直接通过上一个 \(cnt\), 直接算出这一个 \(cnt\)呢?

\(100 pts\) 做法: 本来想写个离散化,但是考虑到代码的整洁性, 直接使用用了std::map; 将取走记为正,放回记为负(方便计算贡献)
然后套个树状数组进行维护单点修改和查询区间和,你每次去做 \(cnt\) 的时候,先二分寻找第一次取完的位置, 然后直接更新贡献。

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 2e5 + 10;

ll blocks[maxn];
int redis[maxn];

struct Opt {
    int t, det, q, op;
}opt[maxn];

map<int,int> dis;

int C[maxn];

int n,q;

void ADD(int x, int v) {for(;x<=n+10;x+=x&-x) C[x]+=v;}
ll query(int x) {ll ans=0;for(;x;x-=x&-x) ans+=C[x];return ans;}

void add(int x,int det){
    ADD(1, det); ADD(x + 1, -det);
}

int main(){
    //freopen("moni.in", "r", stdin);
    //freopen("moni.out", "w", stdout);
    scanf("%d%d", &n, &q);
    dis[0] = 1; // add void point
    for(int i = 1; i <= n; ++i){
        char buf[5];
        int a, b;
        scanf("%s%d%d", buf, &a, &b);
        opt[i].t = a;
        opt[i].det = b;
        if(buf[0] == '+') {
            opt[i].op = 1; opt[i].q = opt[i - 1].q - b;
        } else {
            opt[i].op = 0; opt[i].q = opt[i - 1].q + b;
        }
        if(opt[i].q > 0) dis[opt[i].q] = 0; // add this pos
    }
    int discnt = 0, dismax = 0;
    for (map<int,int>::iterator pr = dis.begin(); pr != dis.end(); ++ pr) {
        pr->second = ++discnt;
        redis[discnt] = pr->first;
        dismax = max(dismax, pr->first);
    }
    for(int i = 1; i < n; ++i){
        if(opt[i].q <= 0) continue;
        int nopos = dis[opt[i].q];
        add(nopos, opt[i + 1].t - opt[i].t);
    }
    for(int i = 1; i <= discnt; ++i){
        blocks[i] = blocks[i - 1] + query(i) * (redis[i] - redis[i - 1]);
    }
    ll blocksum = blocks[discnt];
    for(int i = 1; i <= q; ++i) {
        int cnt;
        scanf("%d", &cnt);
        if(cnt < opt[n].q) {puts("INFINITY"); continue;}
        if(cnt >= dismax) {puts("0"); continue;}
        map<int,int>::iterator it;
        it = dis.lower_bound(cnt);
        ll res = blocksum - blocks[it->second];
        res += 1LL * (it->first - cnt) * query(it->second);
        cout << res << endl;
    }
    return 0;
}

shuxue

题意

这道题题意很明显,公式都给出来了。

题目分析

这道题有一个很朴素的做法, 对于区间内的每个数进行质因数分解,然后忽略掉那个给出的mod值, 答案就是 \((p_1 + 1) * (p_2 + 1) * \cdots\) (\(p_i\) 为质因数的幂次)

例如,如果给出的mod值是13,那么对于\(\forall x \in [L, R]\),将$x = 2^{p_1} \times 3^{p_2} \times \cdots $算出来,那么它不包含13的倍数的因子个数就是排除\(13^{p_k}\),然后做上面的式子。

于是我们就有一个brute force的做法,先把质数筛出来,直接\(O( f(\sqrt{n}))\) 进行质因数分解,\(f(x)\)表示\(x\)以内的质数个数,然后计算答案就可以。总复杂度 \(O( D * f(\sqrt{n}))\)

上面的做法是 \(\le 60 pts\)但是如果对于每一个区间内的数进行分解,那么就会很耗时。所以我们考虑一下优化的做法

我们考虑对于这个区间一个数多出的冗杂计算,如果我们能直接看出这个数的质因子,那我们就可以不用枚举\(2~ \sqrt{n}\)的所有质因子进行试除。可以证明,如果有这样的一个算法,每个数的质因数分解就会在\(ln(n)\)的时间解决。

于是我们枚举所有的质数\(q\),在这个区间内找到第一个能被这个数整除的数,那么下一个能被整除的数就是当前数\(+q\)

我们用\(a[i]\)表示这个位置还剩余的数是多少,显然,在初始状态时\(a[i] = i\),每次找到因子\(p\),我们就进行如下更新\(a[i] /= p\)

\(a[i] = 1\)时,表示这个数已经分解完毕。至此,我们已经将整个算法降为\(O(n \times ln(n))\)

如果考虑到\(10\)MB的内存,我们不难想出这道题需要打表完成(因为线性筛需要12MB内存),当然,你也可以实时进行MillerRobin素数测试,并且运用几个素数的性质,但我选择打表。

那么,如果按上面的分析,用\(a[i]\)储存位于\(i\)的当前值显然是不现实的,因为这样我们需要将数组开到\(a[1e12+10]\),注意到我们只会用到\(D\)的长度,那么我们选择用下标\(0\)去对应\(l\), \(r-l+1\)对应\(r\),就可以了。(这就是一种简单的映射关系)

#inlcude <bits/stdc++.h>

using namespace std;

#define pb push_back
#define forn(i) for(int i=1;i<=(int)(n);++i)
#define rep(i,s,t) for(int i=(int)(s);i<=(int)(t);++i)

const int maxn = 1e6 + 10;

typedef long long qword;

const int primeList[] = {...}

const int maxm = 1e5 + 10;
qword sum[maxm];
qword a[maxm];

inline void Init(int q, qword L, qword R) {
    for (int i = 0; i <= R - L; ++ i) {
        a[i] = i + L;
        while (a[i] % q == 0) {a[i] /= q; if (a[i] == 0) break;}
        sum[i] = 1;
    }
}

inline void work(int q, qword L, qword R) {
    Init(q, L, R);

    for(int i = 1; i <= tot && primeList[i] <= R; ++ i) {
        if (primeList[i] == q) continue;
        qword fir = (L / primeList[i] + (L % primeList[i] ? 1 : 0)) * primeList[i];
        for (qword j = fir; j <= R; j += primeList[i]) {
            qword res = 0;
            while (a[j-L] % primeList[i] == 0) {if (a[j - L] == 0) break; res ++; a[j-L] /= primeList[i];}
            sum[j-L] = 1ll * sum[j-L] * (res+1);
        }
    }

    qword ans = 0;
    for(int i=0; i <= R-L; ++i) {
        if(a[i] != 1) sum[i] = 1ll * sum[i] * 2;
        ans += sum[i];
    }

    cout << ans << endl;
}

int main() {
    freopen("shuxue.in","r",stdin);
    freopen("shuxue.out","w",stdout);
    // Euler_prime();
    int t;
    qword L, R;
    cin >> t >> L >> R;
    int q;
    rep(i,1,t) {
        cin >> q;
        work(q,L,R);
    }
}

Boyi

题目分析

(这道题已经搞出了想法,等待回去测评)

说实话我并没有想出应该怎么做,但是这个题意的意思就是,妹子要容易获胜一点。(单生狗万岁)

因为男的是后手,男的获胜的情况是男的有必胜策略,其他的都是N。 于是,我果断选择全输出“N”水一下,期望得分(\(20 pts\)) 结果过了7个点, 简直迷。

转载于:https://www.cnblogs.com/Alessandro/p/9578844.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园的建设目标是通过数据整合、全面共享,实现校园内教学、科研、管理、服务流程的数字化、信息化、智能化和多媒体化,以提高资源利用率和管理效率,确保校园安全。 智慧校园的建设思路包括构建统一支撑平台、建立完善管理体系、大数据辅助决策和建设校园智慧环境。通过云架构的数据中心与智慧的学习、办公环境,实现日常教学活动、资源建设情况、学业水平情况的全面统计和分析,为决策提供辅助。此外,智慧校园还涵盖了多媒体教学、智慧录播、电子图书馆、VR教室等多种教学模式,以及校园网络、智慧班牌、校园广播等教务管理功能,旨在提升教学品质和管理水平。 智慧校园的详细方案设计进一步细化了教学、教务、安防和运维等多个方面的应用。例如,在智慧教学领域,通过多媒体教学、智慧录播、电子图书馆等技术,实现教学资源的共享和教学模式的创新。在智慧教务方面,校园网络、考场监控、智慧班牌等系统为校园管理提供了便捷和高效。智慧安防系统包括视频监控、一键报警、阳光厨房等,确保校园安全。智慧运维则通过综合管理平台、设备管理、能效管理和资产管理,实现校园设施的智能化管理。 智慧校园的优势和价值体现在个性化互动的智慧教学、协同高效的校园管理、无处不在的校园学习、全面感知的校园环境和轻松便捷的校园生活等方面。通过智慧校园的建设,可以促进教育资源的均衡化,提高教育质量和管理效率,同时保障校园安全和提升师生的学习体验。 总之,智慧校园解决方案通过整合现代信息技术,如云计算、大数据、物联网和人工智能,为教育行业带来了革命性的变革。它不仅提高了教育的质量和效率,还为师生创造了一个更加安全、便捷和富有智慧的学习与生活环境。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值