首页 > 其他分享 >11.2 解题报告&CSP-S 2022题解

11.2 解题报告&CSP-S 2022题解

时间:2022-11-02 22:45:31浏览次数:58  
标签:得分 int 题解 long st 11.2 2022 MAX define

T1

用时:\(1\) h
期望得分:\(70\) ~ \(80\)
实际得分:\(55\)
这题考场写了个常数比较小的 \(O(n^3)\) 的做法,期望得分 \(75\) 左右,但是由于 bfs 忘记打标记导致 MLE 和 TLE,挂掉 \(25\) 分。

正解是枚举 B 和 C,并 bfs 对 B C 分别预处理出权值前三大的点,并且满足这个点到 B 或 C 和 到 \(1\) 的距离都是 \(\le k\) 的,直接对于所有的不重点的四元组求一下权值和,然后取 \(\max\) 即可,复杂度 \(O(n^2)\)。

#include<bits/stdc++.h>
#define ll long long
//#define int unsigned long long
#define ull unsigned long long
#define lc(k) k<<1
#define rc(k) k<<1|1
#define lb lower_bound
#define orz cout<<"gzn ak ioi\n"
const int MAX=2510;
const int MOD=1e9+7;
using namespace std;
inline char readchar() {
	static char buf[100000], *p1 = buf, *p2 = buf;
	return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
inline ull read() {
#define readchar getchar
	ull res = 0, f = 0;
	char ch = readchar();
	for(; !isdigit(ch); ch = readchar()) if(ch == '-') f = 1;
	for(; isdigit(ch);ch = readchar()) res = (res << 1) + (res << 3) + (ch ^ '0');
	return f ? -res : res;
}
inline void write(ull x) {
    if(x<0){putchar('-');x=-x;}
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
int n,m,K,vis[MAX],tong[MAX][MAX];
vector<int> s[MAX],a[MAX];
queue<pair<int,int> > q;
void bfs(int u){
	memset(vis,0,sizeof vis);
	q.push(make_pair(u,-1));
	while(!q.empty()){
		auto f=q.front();q.pop();
		if(vis[f.first]||f.second>K) continue;
		vis[f.first]=1;
		if(u!=f.first){
			tong[u][f.first]=1;
//			a[u].push_back(f.first);
		}
		for(int v:s[f.first])
			q.push(make_pair(v,f.second+1));
	}
	return ;
}
//priority_queue<pair<int,int> > q2;
ull w[MAX];
signed main(){
	n=read(),m=read(),K=read();
	for(int i=2;i<=n;i++) w[i]=read();
	for(int i=1;i<=m;i++){
		int u=read(),v=read();
		s[u].push_back(v);
		s[v].push_back(u);
	}
	for(int i=1;i<=n;i++) bfs(i); 
	for(int i=2;i<=n;i++)
		for(int j=2;j<=n;j++)
			if(tong[1][j]&&tong[i][j])
				a[i].push_back(j);
	for(int i=2;i<=n;i++)
		sort(a[i].begin(),a[i].end(),[](int x,int y){
			return w[x]>w[y];
		});
	ull ans=0;
	for(int i=2;i<=n;i++)
		for(int j=2;j<=n;j++){
			if(!tong[i][j]) continue;
			for(int k=0;k<min(3ll,(ll)a[i].size());k++)
				for(int q=0;q<min(3ll,(ll)a[j].size());q++){
					int x=a[i][k],y=a[j][q];
						ans=max(ans,w[i]+w[j]+w[x]+w[y]);
				}
		}
	cout<<ans;
	return 0;
}

T2

用时:\(30\) min
期望得分:\(60\)
实际得分:\(60\)
由于前面写T4和T1占了太长时间,这题只码了一个 \(60\) 的暴力上去。

显然题目是要求你求出原矩阵的一个子矩阵中行最小值最大的那个最小值。

正解是考虑对于 A 的每种决策,根据正负,B只会做出选择最大值或最小值的决策,所以 A 只会有四种可能的决策:选正数最大,正数最下,负数最大,负数最小,\(0\) 可以随便归入一类。

那就直接开 \(6\) 个 ST 表,分别维护上面的 \(6\) 个最值,直接枚举八种情况求最 \(\max\) 即可。

复杂度 \(O(q(\log n+\log m)+n+m)\)。

#include<bits/stdc++.h>
#define ll long long
#define int long long
//#define ull unsigned long long
#define lc(k) k<<1
#define rc(k) k<<1|1
#define lb lower_bound
#define orz cout<<"gzn ak ioi\n"
const int MAX=1e6+10;
const int MOD=1e9+7;
using namespace std;
inline char readchar() {
	static char buf[100000], *p1 = buf, *p2 = buf;
	return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
inline int read() {
#define readchar getchar
	int res = 0, f = 0;
	char ch = readchar();
	for(; !isdigit(ch); ch = readchar()) if(ch == '-') f = 1;
	for(; isdigit(ch);ch = readchar()) res = (res << 1) + (res << 3) + (ch ^ '0');
	return f ? -res : res;
}
inline void write(int x) {
    if(x<0){putchar('-');x=-x;}
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
int n,m,q,a[MAX],b[MAX],st[8][MAX][20];
int lg[MAX];
/*
0 A 正大
1 A 正小
2 A 负大
3 A 负小
4 B 最大
5 B 最小
*/ 
void init(int i){
	int len=(i<4)?n:m;
	if(i&1){//min 
		for(int j=1;j<=20;j++)
			for(int k=1;k+(1l<<j)-1<=len;k++)
				st[i][k][j]=min(st[i][k][j-1],st[i][k+(1ll<<(j-1))][j-1]);
	}
	else{
		for(int j=1;j<=20;j++)
			for(int k=1;k+(1l<<j)-1<=len;k++)
				st[i][k][j]=max(st[i][k][j-1],st[i][k+(1ll<<(j-1))][j-1]);
	}
}
int ask(int i,int l,int r){
	int x=lg[r-l+1];
	if(i&1) return min(st[i][l][x],st[i][r-(1ll<<x)+1][x]);
	else return max(st[i][l][x],st[i][r-(1ll<<x)+1][x]);
}
signed main(){
	n=read(),m=read(),q=read();
	lg[0]=-1;
	for(int i=1;i<=max(n,m);i++) lg[i]=lg[i>>1]+1;
	for(int i=1;i<=n;i++){
		a[i]=read();
		if(a[i]>=0){
			st[0][i][0]=st[1][i][0]=st[3][i][0]=a[i];
			st[2][i][0]=-1e18;
		}
		else{
			st[0][i][0]=st[2][i][0]=st[3][i][0]=a[i];
			st[1][i][0]=1e18;
		}
	}
	for(int i=1;i<=m;i++){
		b[i]=read();
		st[4][i][0]=st[5][i][0]=b[i];
	}	
	for(int i=0;i<=5;i++) init(i);
	while(q--){
		int ans=-1e18;
		int l1=read(),r1=read(),l2=read(),r2=read();
		ans=max(ans,min(ask(0,l1,r1)*ask(4,l2,r2),ask(0,l1,r1)*ask(5,l2,r2)));
		if(ask(1,l1,r1)!=1e18) ans=max(ans,min(ask(1,l1,r1)*ask(4,l2,r2),ask(1,l1,r1)*ask(5,l2,r2)));
		if(ask(2,l1,r1)!=-1e18) ans=max(ans,min(ask(2,l1,r1)*ask(4,l2,r2),ask(2,l1,r1)*ask(5,l2,r2)));
		ans=max(ans,min(ask(3,l1,r1)*ask(4,l2,r2),ask(3,l1,r1)*ask(5,l2,r2)));
		write(ans);
		putchar('\n');
	}
	return 0;
}

T3

用时:\(30\) min
期望得分:\(40\)
实际得分:\(40\)
这题是最后写的,因为题面很长,这题主要难度在读题,一句话概括题意就是:

给定一个有向简单图,有若干删边加边操作,在每次操作后询问是否满足所有点的出度均为 \(1\)。

考虑哈希维护这个东西,维护一个出度为 \(1\) 的集合 \(A\),把它哈希成所有点的编号平方和*对应出度,当 \(A\{1,2,3\dots n\}\) 时输出 YES。

复杂度 \(O(n)\)。

#include<bits/stdc++.h>
#define ll long long
#define int long long
//#define ull unsigned long long
#define lc(k) k<<1
#define rc(k) k<<1|1
#define lb lower_bound
#define orz cout<<"gzn ak ioi\n"
const int MAX=1e6+10;
const int MOD=1e9+7;
using namespace std;
inline char readchar() {
	static char buf[100000], *p1 = buf, *p2 = buf;
	return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
inline int read() {
#define readchar getchar
	int res = 0, f = 0;
	char ch = readchar();
	for(; !isdigit(ch); ch = readchar()) if(ch == '-') f = 1;
	for(; isdigit(ch);ch = readchar()) res = (res << 1) + (res << 3) + (ch ^ '0');
	return f ? -res : res;
}
inline void write(int x) {
    if(x<0){putchar('-');x=-x;}
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
int n,m,sum1,sum2,sum3[MAX],sum4[MAX];
signed main(){
	n=read(),m=read();
//	mt19937 Rand(time(0));
	for(int i=1;i<=n;i++) sum1+=(i*i);
	for(int i=1;i<=m;i++){
		int u=read(),v=read();
		sum2+=u*u;
		sum3[v]+=u*u;
		sum4[v]+=u*u;
	}
//	for(int i=1;i<=n;i++) cout<<sum3[i]<<" ";
	int q=read();
	while(q--){
		int opt=read();
		if(opt==1){
			int u=read(),v=read();
			sum2-=u*u;
			sum3[v]-=u*u;
		}
		else if(opt==2){
			int u=read();
			sum2-=sum3[u];
			sum3[u]=0;
		}
		else if(opt==3){
			int u=read(),v=read();
			sum2+=u*u;
			sum3[v]+=u*u;
		}
		else{
			int u=read();
			sum2+=sum4[u]-sum3[u];
			sum3[u]=sum4[u];
		}
//		cout<<sum1<<" "<<sum2<<endl;
//		for(int i=1;i<=n;i++) cout<<sum3[i]<<" ";
//		puts(""); 
		if(sum1==sum2) puts("YES");
		else puts("NO");
	}
	return 0;
}

T4

考场用时:\(2\) h
期望得分:\(44\)
实际得分:\(48\)
这题调了大约一个小时,据说正解是动态dp或者神奇树剖,不会。

标签:得分,int,题解,long,st,11.2,2022,MAX,define
From: https://www.cnblogs.com/wapmhac/p/16852832.html

相关文章

  • 2022-11-2学习内容
    1.外部存储空间1.1FileWriteActivity.javapackagecom.example.chapter06;importandroidx.appcompat.app.AppCompatActivity;importandroid.os.Bundle;importan......
  • 2022_11_2
    ......
  • 【2022.11.2】Vue基础学习(7)
    内容详细1vue3介绍1.性能的提升打包大小减少41%初次渲染快55%,更新渲染快133%内存减少54%2.源码的升级使用Proxy代替defineProperty实现响应式......
  • CSP2022 游寄
    今年还是很寄考场上感觉真的没脑子。上来\(T1\)就给我整蒙了,想到原来看过的三元环计数,偏了然后在四个题之间反复横跳,觉得T2应该可做,策略就是取几个最值,T3比较离谱,T4想......
  • 【2022-11-02】前端Vue框架(七)
    一、Vue3基本介绍1.性能的提升打包大小减少41%初次渲染快55%,更新渲染快133%内存减少54%2.源码的升级使用Proxy代替defineProperty实现响应式......
  • CSP2022题目乱写
    官方数据没出,根据目前已知信息瞎写,有错误请帮忙指出假期计划要找\(1-a-b-c-d-1\)的形式,不想偏的话应该能想到预处理一部分然后拼接预处理形式相同的部分\(......
  • CSP-S 2022 VP 记
    19:15开始VP的(19:15先开T1,感觉不难,只是点的判重需要点功夫。19:30开T2,发现很简单,开码。19:40感觉T2很多细节,先开T3,发现题意等价于判断所有点的出度是否为\(1\)。2......
  • P8671 [蓝桥杯 2018 国 AC] 约瑟夫环 题解
    约瑟夫环有\(\mathcalO(n)\)做法相信大家都知道。这里就不在介绍了,这里给出一个不知道这个结论的\(\mathcalO(n\logn)\)简单做法。考虑直接模拟题意,每次循环往后数......
  • [题解]CF1327F
    首先拆位,然后考虑限制会带来什么。要求与起来是\(1\)的必须全是\(1\),差分打个标记。要求与起来是\(0\)的必须至少有一个\(0\),考虑如何计数。计数问题有可能是动态......
  • 求和及求平均-while循环语句的应用-2022-11-2
    packagescanner;importjava.util.Scanner;publicclassDemo04{publicstaticvoidmain(String[]args){Scannerscanner=newScanner(System.in);......