• 2020牛客NOIP赛前集训营-提高组(第二场)


    Before the solution

    这场数据实在是 太 弱 了

    我和 @ZigZagKmp 分别造了 B 和 D 的 hack 数据,并一通操作之后联系上了命题人,命题人将 hack 数据加入了正式数据。

    希望能够重测吧 2020.10.22 7:44

    upd2020/10/22 14:30 重测完了,我排名没变?


    A GCD

    Statement

    我们定义 (f(x)=gcd(x)(1) 之外的所有因子 ())

    (x)(1) 外所有因子的 (gcd)

    询问 (sum_{i=a}^b f(i))

    题解

    考虑这些数,除了可以表示为 (x=p^k) 形式的数,其他的数 (x) 都至少有两个质因子,即 (f(x)=1)

    也就是说 (f(x) = egin{cases} p & x = p^k\ 1 & ext{otherwise} end{cases} )

    用欧拉筛晒出 ([1,b]) 中的质数,再枚举这些质数的次幂即可。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    #define int long long
    
    template < typename Tp >
    inline void read(Tp &x) {
    	x = 0; int fh = 1; char ch = 1;
    	while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    	if(ch == '-') fh = -1, ch = getchar();
    	while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
    	x *= fh;
    }
    
    template < typename Tp >
    inline void biread(Tp &x) {
    	x = 0; int fh = 1; char ch = 1;
    	while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    	if(ch == '-') fh = -1, ch = getchar();
    	while(ch >= '0' && ch <= '9') x = x * 2 + ch - '0', ch = getchar();
    	x *= fh;
    }
    
    bool p[10000007];
    signed prim[10000007], cnt;
    int a, b;
    
    void prime(void) {
    	p[1] = true;
    	for(int i = 2; i <= b; i++) {
    		if(p[i] == false) prim[++cnt] = i;
    		for(int j = 1; j <= cnt && i * prim[j] <= b; j++) {
    			p[i * prim[j]] = true;
    			if(i % prim[j] == 0) break;
    		}
    	}
    }
    
    inline void Init(void) {
    	read(a); read(b);
    }
    
    long long ans;
    
    inline void Work(void) {
    	prime();
    	for(signed i = 1; i <= cnt; i++) {
    //		int j = prim[i];
    		for(long long j = prim[i]; j <= (long long)b; j = j * (long long)prim[i]) {
    			if(j >= a) ans += prim[i] - 1;
    		}
    	}
    	ans += (long long)b - (long long)a + 1ll;
    //	for(int i = a; i <= b; i++) {
    //		if(p[i]) ans++;
    //		else ans += i;
    //	}
    	printf("%lld
    ", ans);
    }
    
    signed main(void) {
    	Init();
    	Work();
    	return 0;
    }
    

    B 包含

    题外话

    进行 Hack 活动时校 OJ 的场景。

    Statement

    我们定义 (A) “包含” (B) 的概念是 (A operatorname{and} B=B) ,其中 (operatorname{and}) 是位运算中的“按位与”。

    现在给出一个集合 (Q) ,这个集合 (n) 个正整数,(m) 次询问。每次询问给出一个数字 (x) ,请回答集合 (Q) 中是否有一个数字包含 (x)

    题解

    观察到值域为 (10^6) ,肯定从值域搞事情,很容易想到枚举是否删除二进制位。

    发现 (n) 远小于 (T),直接预处理值域内的答案, (O(1)) 回答每个询问即可。

    可以通过 dfs 每一个输入的 (a_i),对于 (a_i) 中每个为 (1) 的二进制位,dfs 是否删除。

    同时,通过记忆化优化时间,因为如果一个数 (p) 已经被搜索过,就没必要再对 (p) 进行处理。

    时间复杂度为 (O( ext{值域}+T))

    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    template < typename Tp >
    inline void read(Tp &x) {
    	x = 0; int fh = 1; char ch = 1;
    	while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    	if(ch == '-') fh = -1, ch = getchar();
    	while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
    	x *= fh;
    }
    
    template < typename Tp >
    inline void biread(Tp &x) {
    	x = 0; int fh = 1; char ch = 1;
    	while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    	if(ch == '-') fh = -1, ch = getchar();
    	while(ch >= '0' && ch <= '9') x = x * 2 + ch - '0', ch = getchar();
    	x *= fh;
    }
    
    const int maxn = 100000 + 7;
    
    int n, T;
    bool quality[1000007];
    
    ////vector <int> v;
    
    void dfs(int x, int step, int p2) {
    	if(p2 > x) return ;
    	if(quality[x]) return ;
    	if(((x >> step) & 1) == 0) {
    		dfs(x, step + 1, p2 * 2);
    		return ;
    	}
    	dfs(x - p2, step + 1, p2 * 2);
    	quality[x - p2] = true;
    	dfs(x, step + 1, p2 * 2);
    	quality[x] = true;
    }
    
    inline void Init(void) {
    	read(n); read(T);
    	for(int i = 1, x; i <= n; i++) {
    		read(x);
    		dfs(x, 0, 1); quality[x] = true;
    	}
    }
    
    inline void Work(void) {
    	while(T--) {
    		int x; read(x);
    		if(quality[x]) puts("yes");
    		else puts("no");
    	}
    }
    
    signed main(void) {
    	Init();
    	Work();
    	return 0;
    }
    

    C 前缀

    Statement

    牛牛有一个 (s) 串, (s) 串仅由 (26) 个小写英文字母组成,他现在将 (s) 串进行了无限次的复制扩展成了一个无限循环串。

    例如一开始 s="abc",那么牛牛就会将其变为 "abcabcabc..."

    若某个字符串保留其原本字符出现的顺序,并且按照顺序取出若干个字符。可以不连续,可以不取。

    我们称取出的这若干个字符连成的字符串为一个子序列。

    若连续取出某个字符串的前 (k) 个字符,组成一个子串,我们称该字符串为原串长度为 (k) 的前缀。

    对于一个字符串 (t) ,若某字符串的至少一个子序列为 (t) 。则称它是一个“含 (t) 序列串”

    牛牛想要知道对于给定的 (t) ,他想要知道 (s) 的一个最短前缀满足它是一个“含 (t) 序列串”,它的长度有多长?

    由于答案可能非常大,所以他要求你输出答案对 (998244353) 取余数后的结果即可。

    特别的,如果S串不存在任何一个前缀满足他是一个“含 (t) 序列串”,请输出" (-1) "表示无解。

    (t) 串中除了 (26) 个英文字母以外还会出现"*",表示一个通配符。统配符可以视为任意字母。

    例如循环(s)串为"(abcabcabcabc)...",t串为"(a*ca)"时,最短含(t)序列前缀长(4)。而当(t)串为"(a**ca)"时,最短含(t)序列前缀长(7)

    除此之外,牛牛输入的t串还可能非常非常长,最长可以达到(10^{10^{5}})这么长。

    所以他想了一种压缩方法,来快速读入(t)串。

    具体来说,它输入的(t)串中除了"*"和(26)个小写英文字母以外,还会跟有一些正整数。

    在读入字符串时,这些数字表示它前面字母或者"*"重复的次数。

    例如(a5bc*3),表示"(aaaaabc***)"。输入的正整数不含前导(0)

    题解

    恶臭大模拟。

    代码

    
    

    D 移动

    Statement

    牛牛被困在了一个房间里,他可以看到房间的出口,但是想要到达出口,需要经过 (n) 道闸门。我们可以根据这些闸门离牛牛的距离进行编号,离牛牛最近的闸门记为 (1) 号闸门,离牛牛最远的记为 (n) 号闸门。

    牛牛每秒都可以选择前进到下一闸门,后退到上一闸门,或者原地不动。(从起点到第一道闸门,从第 (n) 道闸门到出口的时间也是一秒)

    这些闸门在一些时刻是关闭的,无法通行,剩下的时刻是开启的,可以通行。

    注意:如果牛牛所在的位置有一个闸门即将关闭,他在此时选择原地不动,就会被闸门夹到,变成牛排。牛牛想在不变成牛排的前提下走到出口,他想知道最短需要多少秒才能走到出口,如果他永远无法走到出口,输出 (-1)

    在每一秒内,首先牛牛进行移动,然后闸门进行开/关的动作。

    题解

    代码

    
    
  • 相关阅读:
    Python 爬取网易云歌手的50首热门作品
    对于AES和RSA的个人理解
    sqlzoo
    项目部署 uwsgi+nginx+crm
    nginx学习
    redis补充知识--- 缓存击穿、缓存雪崩、缓存穿透
    redis-cluster 搭建
    redis主从复制
    redis-sentinel (哨兵)
    redis 发布订阅
  • 原文地址:https://www.cnblogs.com/liubainian/p/13849321.html
Copyright © 2020-2023  润新知