首页 > 其他分享 >CSP模拟-8

CSP模拟-8

时间:2023-07-28 20:44:07浏览次数:16  
标签:differ int sum mid include CSP 模拟 指针

今天T1终于看懂辣。。。。但今天名次最低QAQ。T1没算空间复杂度,直接炸QAQ

T1 Coprime 2

今天T1确实简单,将输入的数的质数公因数用埃氏筛筛出来,用一个数组存下来。每次将质因数的倍数用 \(flag\) 存下 \(true\) ,表示这个数存在因数与输入的数重复的情况,让后就没有辣。

正确性的话:一个合数因数一定会被分解成一个或多个质因数,所以每次找质因数就行辣。(我相信你们都明白吧QAQ)

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector> 

using namespace std;

int n, a[5211314], m;
int gcd_sum, ans[2000010], sum, is_gcd[2000010], rec_gcd[2000010];
bool barrel[2000010], is_prime[2000010], flag[2000010];

void Prime() {
	//正经的埃氏筛
	memset(is_prime, true, sizeof(is_prime));
	for (int i = 2; i <= m; ++ i) {
		if (is_prime[i] == false) continue;
		for (int j = i; j <= m; j = j + i) {
			is_prime[j] = false;
			//找输入的数的质因数
			if (barrel[j] == true && rec_gcd[i] == false) {
				//如果i的倍数是输入的数并且质因数i没有被存过
				is_gcd[++ gcd_sum] = i;
				rec_gcd[i] = true;
				//这里记录的原因是保证复杂度
			}
		}
	}
	return;
}

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++ i) {
		scanf("%d", &a[i]);
		barrel[a[i]] = true;
		//将输入的数用桶先存下来
	}
	Prime();
	for (int i = 1; i <= gcd_sum; ++ i) {
		for (int j = is_gcd[i]; j <= m; j += is_gcd[i]) {
			//将每个质数因数的倍数标记
			flag[j] = true;
		}
	}
	for (int i = 1; i <= m; ++ i) {
		if (flag[i] == false) {
			//不存在输入的数的质因数
			ans[++ sum] = i;
		}
	}
	//输出
	printf("%d\n", sum);
	for (int i = 1; i <= sum; ++ i) {
		printf("%d\n", ans[i]);
	}
	return 0;
}

T2 Dist Max 2

又是逆天二分QAQ,永远写不对的边界条件,我真服了。

看见找最小值的最大值,一眼丁真鉴定为二分答案

设我们现在已经枚举到 \(mid\),所以我们这时必定会存在 \(i, j\) 满足 \(\left| x_i - x_j \right| \geq mis\) 并且满足 \(\left| y_i - y_j \right| \geq mid\) 。

此时我们直接遇事不决先排序,将点以 \(x\) 为关键字进行升序排序,然后维护双指针就行了。

我们的双指针 \(l,r\) 表示左区间 \(1 \sim l\) 以 \(l\) 为结尾,右区间 \(r \sim n\) 以 \(r\) 为右端点。这时我们要保证区间 \(1 \sim l\) 的每一个点的横坐标与区间 \(r \sim n\) 的每一个点的横坐标的差大于我们二分到的 \(mid\)。将这两个符合差为 \(mid\) 要求的区间内点的纵坐标 \(Y\) 的最大值与最小值分别与另一区间内纵坐标 \(Y\) 的最小值最大值作差,判断是否大于等于 \(mid\)。若大于,则符合题目要求,返回真。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;

int n;

struct Picture {
	int x, y;
	bool operator < (const Picture & b) const {
		if (x != b.x) return x < b.x;
		return y < b.y;
	}//sort的时候用 
}a[1000100];

bool check(int differ) {
	int MaxY = -1e9, MinY = 1e9;
	//在l之前Y轴的最值 
	for (int r = 1, l = 0; r <= n; ++ r) { 
		//这里面的l表示左半部分的右端点,r表示右半部分的左端点
		//l就是左指针,r就是右指针 
		while (l < r && a[r].x - a[l + 1].x >= differ) {
			//若存在更小的X轴之差符合差最小值得differ的条件,就更新l的值 
			MaxY = max(MaxY, a[l + 1].y);
			MinY = min(MinY, a[l + 1].y);
			//将左指针新包含的范围内的MaxY和MinY更新 
			l ++;
		}
		if (MaxY - a[r].y >= differ) return true;
		if (a[r].y - MinY >= differ) return true;
		//判断左边的Y的最值与右侧的Y的最值的差是不是大于differ 
		//在循环里我们相当于将右指针后面的数全部枚举了一遍最大值,最小值 
		//左指针除了l=r=1的时候处理右指针,其他时候都是左指针跟着右指针移动
		//所以在右指针更新的时候,左指针左边的MaxY与MinY也都被更新了,正确性可以保证 
	}
	return false;
}

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; ++ i) {
		scanf("%d%d", &a[i].x, &a[i].y);
	}
	sort(a + 1, a + 1 + n);
	int l = 0, r = 1e9, ans = 0;
	while (l <= r) {
		//二分找最值 
		int mid = (l + r) >> 1;
		if (check(mid)) {
			l = mid + 1;
			ans = mid;
		}
		else r = mid - 1;
	}
	printf("%d\n", ans);
	return 0;
}

PS:顺带附上找最最大的最小值

while (l <= r) {
	int mid = (l + r) >> 1;
	if (check(mid)) {
		r = mid - 1;
		ans = mid;
	}
	else l = mid + 1;
}

T3 [ABC221H] Count Multiset

这边建议[这篇题解](「解题报告」[ABC221H] Count Multiset - K8He - 洛谷博客 (luogu.com.cn))。写的很好,复杂度优。

#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <cstdio>

#define mod 998244353

using namespace std;
typedef long long ll;

int n, m, f[5210][5210], g[5210][5210], sum[5210][5210];

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++ i) {
		if (i <= m) 
			f[i][0] = 1;
		for (int j = 1; j <= n; ++ j) {
			if (j >= i) 
				f[i][j] = g[i][j] = f[i][j - i];
			sum[i][j] = (sum[i - 1][j] + g[i][j]) % mod;
			f[i][j] = ((f[i][j] + sum[i - 1][j]) % mod - sum[max(0, i - m - 1)][j] + mod) % mod;
		}
	}
	for (int i = 1; i <= n; ++ i) {
		cout << g[i][n] << endl;
	}
	return 0;
}

T4 Julia the snail

数据加强版,吉司机线段树不会,咕。

总结

本次考试分数最高,但名词最低QAQ。T1直接炸,没考虑空间复杂度,下一次不能再犯辣。T2没看见是整数,不敢开 \(long long\),开了 \(longdouble\) 输出浮点,又炸。![[23FDBE81.jpg]]

标签:differ,int,sum,mid,include,CSP,模拟,指针
From: https://www.cnblogs.com/jueqingfeng/p/17588869.html

相关文章

  • CSP模拟8
    闲话今天老吕从国赛,带来一个消息:“省选可能取消,完全看NOIP成绩”。不过对我没什么影响,反而还开心一些。A.Coprime题目大意给定一个长度为\(n\)的数列\(a\),要求出\(1\simm\)中与\(a\)中的所有元素互质的数。数据范围:\(1\\leq\n,m\\leq\10^5,1\\leq\a_i\\l......
  • 「赛后总结」暑假集训:20230727 CSP 模拟赛
    「赛后总结」20230727CSP模拟赛点击查看目录目录「赛后总结」20230727CSP模拟赛总结题解T1卷T2简单题T3粉丝T4字符串已经入园两年了吗。好快哦。2023年7月28日20:04:早上就写完了但忘了发了。以下内容均写于「2023年7月27日」。前两天题还没改完呢,有......
  • wpf在设计器模式利用模拟数据展现控件
    使用VisualStudio开发WPF应用程序时,控件显示需要的数据如果来路比较“苦难”,比如来自数据库,JSON文件,复杂计算等,这时候,如果想看到控件带有数据的展示效果,需要启动调试,这很麻烦。我们可以在XAML中使用designtime语法给控件赋予模拟数据MSDN教程,也可以在后台使用csharp代码判断当......
  • c# WinForm 引用 Chrome 模拟操作
    Nuget CefSharp.WinForms publicForm1(){InitializeComponent();chromiumWebBrowser1.LoadingStateChanged+=ChromiumWebBrowser1_LoadingStateChanged;}privatevoidbutton1_Click(objectsender,EventArgs......
  • Window系统下模拟Linux环境的工具
    [b][color=red]强大的Cygwin[/color][/b]:[url]http://cygwin.com/install.html[/url]OracleunderCygwin-EduUnix[url]http://eduunix.ccut.edu.cn/index2/html/oracle/O'Reilly%20-%20Perl.For.Oracle.DBAs.eBook-LiB/oracleperl-CHP-2-SECT-4.......
  • Android shell模拟物理按键
    Androidshell模拟物理按键在Android开发中,有时候我们需要模拟物理按键的操作,例如模拟点击返回键、Home键等。Android提供了一个能够在命令行中模拟按键操作的工具——input。input命令简介input命令是Android系统中的一个工具,用于模拟按键事件。通过使用不同的参数,我们可以模拟......
  • 济南 CSP-J Day 4
    SolutionT1出现次数原题链接4102:出现次数简要思路利用类似前缀和的“后缀和”来记录下每个数后面有几个未重复出现的数,定义一个\(f\)数组来判断是不是第一次出现(实现去重)。完整代码#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;constint......
  • CSP 模拟 6
    T1排序基本是原题CF1375E好像是简单题,考虑这个排列\(\pi\)的逆排列\(\pi^{-1}\)(如果排列是\(a_i\),则逆排列为\(b_{a_i}=i\)),因为逆序对的定义是序列编号和数值大小关系不一样,所以在逆排列中逆序对和原排列相同,对逆排列做冒泡排序,因为冒泡排序交换的是相邻值的位置,对其他值......
  • CSP模拟7
    A.卷一道可爱的树形DP喵!题目保证了\(w_i\)是在给定范围内随机生成的,所以不会炸精度。首先明确题意,是求出最大乘积独立集之后取模,而不是边乘边取模。边乘边取模会炸,例如\(10^9+8\)对\(10^9+7\)取模后小于\(2\),但显然\(10^9+8>2\)。那怎么办呢?高精?可以用我们......
  • CSP 模拟 5
    T1第一题贪心,观察肯定是从较浅的点上来一个士兵或者从根节点来一个士兵,用set或者vector启发式合并维护这个过程即可点击查看代码#include<bits/stdc++.h>#defineN100005#defineinf0x3f3f3f3f#definepiipair<int,int>#definempmake_pairusingnamespacestd;......