首页 > 其他分享 >第十五节 数论 - 2

第十五节 数论 - 2

时间:2023-07-26 13:55:17浏览次数:31  
标签:status 10 数论 time test memory 第十五 Accepted

AT_agc017_b 题解

洛谷链接&Atcoder 链接

本篇题解为此题较简单做法,请放心阅读。

题目简述

一共有 \(n\) 个格子,给定两个整数 \(A,B\) 分别位于第 \(1\) 和第 \(n\) 格,中间有 \(n−2\) 个空格。询问是否存在一种填数方案满足任意相邻两个数之差的绝对值在 \([C,D]\) 之间。

依次输入 \(n,a,b,c,d\)。

若能,输出 YES;反之输出 NO

思路

遇事不决先看数据范围,发现数据范围 \(3 \le N \le 5 \times 10^5\),那么时间复杂度在 \(O(N)\) 以内就可以接受,本篇题解就详细解释一下 \(O(N)\) 的算法。

首先可以想到 \(O(N)\) 的复杂度就是遍历 \(N\),可以想到枚举在 \(A,B\) 之间填了 \(i\) 个数,从 \(0 \sim N-2\) 遍历即可,遍历时进行判断,如果满足要求可直接输出 YES,否则遍历完后输出 NO

接着可以先把区间 \([C,D]\) 转化为区间 \([0,D-C]\),那么判断条件就需要判断 \(C\) 的合法性及可行性

\[B - (2 \times (i + 1) - N) \times C \]

接着可写出判断条件的边界条件,首先是最大值即右区间,通过右区间 \(D-C\) 很容易得出:

\[A + i \times (D - C) + D \]

以及左区间

\[A + (N - 2 - i) \times (C - D) + C \]

如果合法的 \(C\) 在此区间内则输出 YES,否则在遍历后输出 NO

注意:因为均为闭区间所以需是 \(\le\) 而不是 \(<\)

经过以上分析及转化,很容易即可得出代码了。

提交记录

\[\text{The End!} \]

AT_arc154_b 题解

洛谷链接&Atcoder 链接

本篇题解为此题较简单做法较少码量,并且码风优良,请放心阅读。

题目简述

给定两个长度为 \(n\) 的字符串 \(S,T\),定义一次操作可取出 \(S\) 的首位,插到 \(S\) 的任意位置。

求最少的操作次数使 \(S\) 变成 \(T\),无解输出 -1

思路

首先很容易想到如果 \(S\) 和 \(T\) 的某个字母的个数不同,那么 \(S\) 不可能变为 \(T\)。因为不可能凭空变出一个字母。通过两个桶数组即可记录 \(S,T\) 的每个字母个数

int cnt_s[30], cnt_t[30];
for(int i = 0; i < n; i ++) 
	cnt_s[s[i] - 'a'] ++, cnt_t[t[i] - 'a'] ++;	

接着验证 \(S\) 和 \(T\) 的各个字母数量是否一致,一旦不一致立刻输出 -1 即可:

for(int i = 0; i < 26; i ++) 
		if(cnt_s[i] != cnt_t[i]) {
			cout << "-1\n";
			return 0;
		}

特判 -1 的情况后就很简单了,仅需遍历 \(T\) 即可,在过程中如果 \(S\) 的当前位与 \(T\) 相同,则表示不必进行操作,把之前记录的 \(ans\) 自减即可

经过以上分析,很容易即可得出完整代码了:

#include<iostream>
using namespace std;

int n, cnt_s[30], cnt_t[30], ans = 0; // 必要数组不解释
string s, t; // 模式串和匹配串

int main() {
	cin >> n >> s >> t;
	ans = n - 1; // 因为下标从 0 开始,所以 ans 需初始化为 n - 1
	for(int i = 0; i < n; i ++) cnt_s[s[i] - 'a'] ++, cnt_t[t[i] - 'a'] ++; // 统计字母个数
	for(int i = 0; i < 26; i ++) 
		if(cnt_s[i] != cnt_t[i]) {
			cout << "-1\n"; // 字母个数不相同直接输出
			return 0;
		}
	for(int i = n - 1; i >= 0; i --)
		if(s[ans] == t[i]) ans --; // 满足条件不必操作,ans --
	cout << ans + 1 << endl; // 还是下标问题答案需 +1,建议写下标从 1 开始的
	return 0;
}

提交记录

\[\text{The End!} \]

A. 循环与非

题目描述

给定长度为 \(n\) 的序列 {\(a_n\)},每一个数字都不超过 \(2\) 的 \(k\) 次方。给定 \(m\) 次操作,每次操作形如:

0 x y :将 \(a[x]\) 改为 \(y\)。

1 x y :令 \(t=y\) NAND \(a[0]\) NAND \(a[1]\) NAND \(a[2]\) NAND ... NAND \(a[i\) \(mod\) \(n]\) NAND ... NAND \(a[(x*n-1)\) \(mod\) \(n]\)。

NAND 代表按位与非操作。

求所有计算结果的 \(t\) 的异或和。

输入格式

第一行包含三个正整数 \(n,m,k\)。

接下来一行 \(n\) 个整数 \(a_0 \sim a_{n-1}\)。

接下来 \(m\) 行每行三个整数 \(op,x,y\)。

输出格式

输出一行一个整数表示答案。

样例输入

2 3 3
1 2
1 2 3
0 0 3
1 2 2

样例输出

2

样例输入

7 4 4
4 6 4 7 10 9 11
1 5 7
1 7 14
0 6 7
1 6 5

样例输出

9

数据规模

\(1 \le n,m \le 10^4\),\(0 \le y < 2^k\)

操作 \(0\) 中,\(0 \le x < n\)

操作 \(1\) 中,\(1 \le x < 10^9\)

\(1 \le k \le 30\)

点击查看代码
#include<iostream>
#include<set>
using namespace std;

int m, n, k, a[10005];
set<int> st[30];

int find(int i) { return st[i].empty() ? -1 : *st[i].rbegin(); }

int main() {
	cin >> n >> m >> k;
	int tmp;
	for(int i = 0; i < n; i ++) {
		cin >> tmp;
		for(int j = 0; j < k; j ++)
			if(!(tmp & 1 << j)) st[j].insert(i);
	}
	int opt, x, y, res, t = 0, last;
	while(m --) {
		cin >> opt >> x >> y;
		if(opt == 0)
			for(int i = 0; i < k; i ++)
				if(!(y & 1 << i)) st[i].insert(x);
				else st[i].erase(x);
        else {
			res = 0;
			for(int i = 0; i < k; i ++){
				last = find(i);
				if(last == -1) res += (1ll * x * n + (y >> i & 1) & 1) << i;
				else res += (n - last & 1) << i;
			}
			t ^= res;
		} 
	}
	cout << t;
	return 0;	
}
编译结果
compiled successfully
time: 100ms, memory: 7232kb, score: 100, status: Accepted
> test 1: time: 1ms, memory: 3408kb, points: 10, status: Accepted
> test 2: time: 5ms, memory: 3448kb, points: 10, status: Accepted
> test 3: time: 25ms, memory: 7232kb, points: 10, status: Accepted
> test 4: time: 3ms, memory: 4076kb, points: 10, status: Accepted
> test 5: time: 17ms, memory: 5248kb, points: 10, status: Accepted
> test 6: time: 2ms, memory: 3544kb, points: 10, status: Accepted
> test 7: time: 10ms, memory: 3720kb, points: 10, status: Accepted
> test 8: time: 10ms, memory: 3604kb, points: 10, status: Accepted
> test 9: time: 18ms, memory: 4716kb, points: 10, status: Accepted
> test 10: time: 9ms, memory: 3476kb, points: 10, status: Accepted

B. 蹦蹦萝卜

题目描述

有一个环状的操场,操场被分割为 \(n\) 个小块,每个小块上写着一个数字。

有一只小白兔站在操场的起点 \(1\),它每次可以跳 \(k\) 个小块,然后拿走等同于它跳之前所站小块上数字数量的胡萝卜,问它跳 \(m\) 次,总共可以拿到几个胡萝卜?

小白兔在 \(i\) 处时,它跳到的下一个位置是 \((i+k)\) \(mod\) \(n + 1\)。

如果能够算出来的话,小白兔就能把所有的胡萝卜都带回家吃啦!

答案对 \(10^9+7\) 取模。

输入格式

第一行包含两个正整数 \(n\) 和 \(k\),

第二行 \(n\) 个正整数 \(a_1...a_n\) 每个小块上的数字,

第三行一个正整数 \(m\)。

输出格式

输出一行一个整数表示答案。

样例输入

5 1
1 10 100 1000 10000
3

样例输出

10101

数据规模

\(1 \le k \le n \le 10^6\),\(1 \le a_i \le 10^6\), \(1 \le m \le 10^{18}\)

点击查看代码
#include<iostream>
#include<set>
using namespace std;

#define MOD 1000000007
int n, k, a[1000005], p[1000005][70], c[1000005][70];
long long m;

int main() {
    cin >> n >> k;
    for(int i = 1; i <= n; i ++) cin >> a[i];
    cin >> m;
    for(int i = 1; i <= n; i ++) {
        p[i][0] = (i + k) % n + 1;
        c[i][0] = a[i];
    }
    for(int j = 1; j <= 60; j ++) {
        for(int i = 1; i <= n; i ++) {
            p[i][j] = p[p[i][j - 1]][j - 1];
            c[i][j] = (c[i][j - 1] + c[p[i][j - 1]][j - 1]) % MOD;
        }
    }
    long long res = 0;
    int x = 1;
    for(int j = 0; j < 63; j ++) {
        if(m & 1LL << j) {
            res += c[x][j];
            x = p[x][j];
        }
    }
    cout << res % MOD << endl;
    return 0;
}
编译结果
compiled successfully
time: 12253ms, memory: 496952kb, score: 100, status: Accepted
> test 1: time: 1775ms, memory: 386052kb, points: 10, status: Accepted
> test 2: time: 106ms, memory: 58732kb, points: 10, status: Accepted
> test 3: time: 1147ms, memory: 262252kb, points: 10, status: Accepted
> test 4: time: 324ms, memory: 116136kb, points: 10, status: Accepted
> test 5: time: 1937ms, memory: 410032kb, points: 10, status: Accepted
> test 6: time: 273ms, memory: 99752kb, points: 10, status: Accepted
> test 7: time: 2433ms, memory: 496952kb, points: 10, status: Accepted
> test 8: time: 1629ms, memory: 360016kb, points: 10, status: Accepted
> test 9: time: 1412ms, memory: 313324kb, points: 10, status: Accepted
> test 10: time: 1217ms, memory: 275484kb, points: 10, status: Accepted

C. 超大范围幂运算

时间:1s 空间:256M

题目描述

有 \(3\) 个整数 \(a, b, c\),求 \(a^b\) \(mod\) \(c\)

输入格式

第一行包含一个整数 \(T\),表示测试数据组数。

对于每组测试数据,包含 \(3\) 个整数 \(a, b, c\)。

输出格式

对于每组测试数据,输出一个整数表示答案。

样例1输入

6
0 0 1
0 0 100
2 5 17
0 10 100
100 0 1000000000000000000
114 514 1919810

样例1输出

0
1
15
0
1
290606

约定与提示

对于 \(100\%\) 的数据,\(1 \le T \le 5000\),\(0 \le a,b \le 10^{18}\); \(1 \le c \le 10^{18}\)

点击查看代码
#include<iostream>
#include<set>
using namespace std;

long long T, a, b, c;

long long qadd(long long a, long long b, long long p) {
    long long res = 0;
    while(b) {
        if(b & 1) res = (res + a) % p;
        a = (a + a) % p;
        b >>= 1;
    }
    return res;
}

long long quickpow(long long x, long long n, long long m){
	if(n == 0)	return 1 % m;
	long long res = quickpow(qadd(x, x, m), n / 2, m);
	if(n & 1) res = qadd(res, x, m);
	return res;
}

int main() {
    cin >> T;
    while(T --) {
        cin >> a >> b >> c;
        printf("%lld\n", quickpow(a, b, c));
    }
    return 0;
}
编译结果
compiled successfully
time: 597ms, memory: 3524kb, score: 100, status: Accepted
> test 1: time: 1ms, memory: 3424kb, points: 0, status: Accepted
> test 2: time: 1ms, memory: 3524kb, points: 20, status: Accepted
> test 3: time: 1ms, memory: 3492kb, points: 20, status: Accepted
> test 4: time: 50ms, memory: 3484kb, points: 20, status: Accepted
> test 5: time: 67ms, memory: 3476kb, points: 20, status: Accepted
> test 6: time: 477ms, memory: 3496kb, points: 20, status: Accepted

标签:status,10,数论,time,test,memory,第十五,Accepted
From: https://www.cnblogs.com/So-noSlack/p/17582271.html

相关文章

  • 第十四节 数论
    $$\text{建议阅读}$$A.优美子数列题目描述数学家小\(Q\)得到了一个长度为\(n\)的数列{\(a_n\)}。小\(Q\)的幸运数字是\(k\),所以他认为,若一个子数列\(a_l\),\(a_l+1\),…,\(a_r\)的和为\(k\)的倍数,则该子数列是优美子数列。小\(Q\)现在想考考你,{\(a_n\)}......
  • (Relax 数论1.26)POJ 1496 Word Index(计算一个字符串在字典中的位置)
    大致题意:(与POJ1850基本一致)输出某个str字符串在字典中的位置,由于字典是从a=1开始的,因此str的位置值就是在str前面所有字符串的个数+1规定输入的字符串必须是升序排列。不降序列是非法字符串要求用循环输入,输入若干组字符串,若输入非法字符串则输出0,但不结束程序,这是和POJ1850......
  • 基础数论
    Updon2023.1.12添加了整除分块和莫比乌斯反演。Updon2023.7.22重新排版,添加、删去了一些内容,修改了一些晦涩难懂的描述,开放阅读。$$\huge\textbf{0x01}\\large\textbf{数论入门}$$"质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。""合数是指在大......
  • PerfView专题 (第十五篇): 如何洞察 C# 中的慢速方法
    一:背景1.讲故事在dump分析旅程中,经常会遇到很多朋友反馈一类问题,比如:方法平时都执行的特别快,但有时候会特别慢,怎么排查?我的方法第一次执行特别慢,能看到慢在哪里吗?相信有朋友肯定说,加些日志不就好了,大方向肯定是没问题的,但加日志的颗粒度会比较粗而且侵入性也比较大,比如......
  • 第十五篇 - Vue添加图标
    参考链接:https://www.yii666.com/blog/45780.html添加图标的两种方式:1.直接使用element-plus/icons-vue(图标名称网址:https://element-plus.gitee.io/en-US/component/icon.html#icon-collection)2.使用svg-sprite-loader自己下载svg图标(SVG图标下载网址:https://www.iconfinder......
  • 数论板子
    exgcd点击查看代码__int128exgcd(__int128as,__int128bs,__int128&x,__int128&y){if(bs==0){x=1;y=0;returnas;}__int128ans=exgcd(bs,as%bs,y,x);y-=(as/bs)*x;returnans;}a&c&lucas点击查看代码......
  • 数论分块
    概念我们考虑这样一个问题:求\(\sum_{i=1}^{k}\lfloor\dfrac{n}{i}\rfloor\)我们以\(n=7,k=7\)为例子,先画出\(f(x)=\dfrac{7}{x}\(1\leqx\leq7)\)的图像因为我们的取值是向下取整的,我们描出所有可能的取值注意到所有的点按照取值可以分成若干段我们可以一次......
  • 20230710-20230711 数论
    数论被薄纱了/kk授课老师:南京大学-朱富海教授20230710裴蜀定理对于给定不全为零的整数的\(a,b\)一定存在一对整数\(x,y\)满足\(ax+by=gcd(a,b)\)。证明:\(a==0\)\(or\)\(b==0\)显然成立;设\(gcd(a,b)=d\),即求证存在\(x,y\)满足\(ax+by=d\),等式两边同时除......
  • 数论专题练习
    数论专题练习A-BeautifulNumbers题意:输入a,b,n,求只包含a,b的n位数并且n位之和为a或b的数量枚举a和b的数量,判断它们的和是否为一个good_number,然后用组合数(详见数论的组合数)求和#include<bits/stdc++.h>usingnamespacestd;constintp=1e9+7;constintMAXN=1e6......
  • 整除分块(数论分块)
    整除分块是为了解决一个整除的求和的问题:sum(floor(n/i))(1<=i<=n) ,如果直接暴力计算复杂度O(n),但整除分块的复杂度为O(2sqrt(n)),其中的2为常数,可以忽略,那么复杂度为O(sqrt(n))下面给出整除分块的模板代码#include<bits/stdc++.h>#definelllonglongusingnamespacestd;ll......