暑假-OI-分析

暑假考题总结

CSP-S 2023

CSP-S T1密码锁

一道很水的题目,我们可以直接用 \(9^5\) 通过。

Code
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <queue>
#include <map>
#include <set>
#define prt printf
#define ll long long
#define int long long
#define spc putchar(' ')
#define ent putchar('\n')
#define pr_ prt("---")
#define prx prt("***")
#define prtn (putchar('N') , putchar('o'))
#define prty (putchar('Y') , putchar('e') , putchar('s'))
using namespace std;

inline int read(){
	int f = 1 , k = 0 ;
	char c = getchar() ;
	while((c < '0') | (c > '9')) { f = (c == '-' ? -1 : 1) ; c = getchar() ;}
	while((c >= '0') & (c <= '9')) { k = (k << 3) + (k << 1) + (c ^ 48) ; c = getchar() ;}
	return f == - 1 ? -k : k ;
}

void output(int now){
	if(now < 0){
		putchar('-');
		output(- now);
	}
	else{
		if(now > 9) output(now / 10);
		putchar((now % 10) ^ 48);
	}
}

const int maxn = 1e5 + 1 , mod = 10;
int n , s1[10] , s2[10] , s3[10] , s4[10] , s5[10] , ans = 0;
bool vis[10][10][10][10][10] , a[10][10][10][10][10][10];

bool check(int i , int j , int k , int l , int r){
	for(int num = 1 ; num<=n ; num++) if(a[num][i][j][k][l][r] == false) return false;
	return true;
}

signed main(){
	n = read() ;
	for(int i=1 ; i<=n ; i++){
		s1[i] = read() , s2[i] = read() , s3[i] = read() , s4[i] = read() , s5[i] = read() ;
		vis[s1[i]][s2[i]][s3[i]][s4[i]][s5[i]] = true;
	}
	for(int i=1 ; i<=n ; i++){
		for(int j=1 ; j<=9 ; j++){
			if(vis[(s1[i] + j) % mod][s2[i]][s3[i]][s4[i]][s5[i]] == false) a[i][(s1[i] + j) % mod][s2[i]][s3[i]][s4[i]][s5[i]] = true;
			if(vis[s1[i]][(s2[i] + j) % mod][s3[i]][s4[i]][s5[i]] == false) a[i][s1[i]][(s2[i] + j) % mod][s3[i]][s4[i]][s5[i]] = true;
			if(vis[s1[i]][s2[i]][(s3[i] + j) % mod][s4[i]][s5[i]] == false) a[i][s1[i]][s2[i]][(s3[i] + j) % mod][s4[i]][s5[i]] = true;
			if(vis[s1[i]][s2[i]][s3[i]][(s4[i] + j) % mod][s5[i]] == false) a[i][s1[i]][s2[i]][s3[i]][(s4[i] + j) % mod][s5[i]] = true;
			if(vis[s1[i]][s2[i]][s3[i]][s4[i]][(s5[i] + j) % mod] == false) a[i][s1[i]][s2[i]][s3[i]][s4[i]][(s5[i] + j) % mod] = true;
		}
		for(int j=1 ; j<=9 ; j++){
			if(vis[(s1[i] + j) % mod][(s2[i] + j) % mod][s3[i]][s4[i]][s5[i]] == false) a[i][(s1[i] + j) % mod][(s2[i] + j) % mod][s3[i]][s4[i]][s5[i]] = true;
			if(vis[s1[i]][(s2[i] + j) % mod][(s3[i] + j) % mod][s4[i]][s5[i]] == false) a[i][s1[i]][(s2[i] + j) % mod][(s3[i] + j) % mod][s4[i]][s5[i]] = true;
			if(vis[s1[i]][s2[i]][(s3[i] + j) % mod][(s4[i] + j) % mod][s5[i]] == false) a[i][s1[i]][s2[i]][(s3[i] + j) % mod][(s4[i] + j) % mod][s5[i]] = true;
			if(vis[s1[i]][s2[i]][s3[i]][(s4[i] + j) % mod][(s5[i] + j) % mod] == false) a[i][s1[i]][s2[i]][s3[i]][(s4[i] + j) % mod][(s5[i] + j) % mod] = true;
		}
	}
	for(int i=0 ; i<=9 ; i++){
		for(int j=0 ; j<=9 ; j++){
			for(int k=0 ; k<=9 ; k++){
				for(int l=0 ; l<=9 ; l++){
					for(int r=0 ; r<=9 ; r++) if(check(i , j , k , l , r) == true) ++ ans;
				}
			}
		}
	}
	return output(ans) , ent , 0 ;
}

CSP-S T2消消乐

这个题目肯定是没有蓝的。

看完题目易得出我们只需要知道当前字母上一个相同字母的下标,去做 \(DP\),我们只需要维护当前字符串是否为回文串就行了。

Code
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <queue>
#include <map>
#include <set>
#define prt printf
#define ll long long
#define int long long
#define spc putchar(' ')
#define ent putchar('\n')
#define pr_ prt("---")
#define prx prt("***")
#define prtn (putchar('N') , putchar('o'))
#define prty (putchar('Y') , putchar('e') , putchar('s'))
using namespace std;

inline int read(){
	int f = 1 , k = 0 ;
	char c = getchar() ;
	while((c < '0') | (c > '9')) { f = (c == '-' ? -1 : 1) ; c = getchar() ;}
	while((c >= '0') & (c <= '9')) { k = (k << 3) + (k << 1) + (c ^ 48) ; c = getchar() ;}
	return f == - 1 ? -k : k ;
}

void output(int now){
	if(now < 0){
		putchar('-');
		output(- now);
	}
	else{
		if(now > 9) output(now / 10);
		putchar((now % 10) ^ 48);
	}
}

signed main() {
	int n = read() , ans = 0; vector<char> s(n + 1) ; vector<int> d(n + 1) , l(n + 1);
	for(int i=1 ; i<=n ; i++) {s[i] = getchar() ; while(('a' > s[i]) | (s[i] > 'z')) s[i] = getchar() ;}
	for(int i=1 ; i<=n ; i++) {
		for(int j=i-1 ; j>0 ; j=l[j] - 1) {
			if(s[i] == s[j]) {l[i] = j ; break ;}
		}
		if(l[i]) d[i] = d[l[i] - 1] + 1 , ans += d[i] ;
	}
	return output(ans) , ent , 0 ;
}
/*
l[i] 存储上一个跟 s[i] 相同字母的下标
l[j] ~ l[i] - 1 构成回文串那么 s[l[i]] == s[l[j] - 1],构成的回文串数量为 l[j] - 1 与前面字母构成的回文串数量 + 1
*/

CSP-S T3结构体

这个题目是一个大模拟,只需要按题意一直维护给出的操作就行了。

Code
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <queue>
#include <map>
#include <set>
#define prt printf
#define ll long long
#define int long long
#define spc putchar(' ')
#define ent putchar('\n')
#define pr_ prt("---")
#define prx prt("***")
#define prtn (putchar('N') , putchar('o'))
#define prty (putchar('Y') , putchar('e') , putchar('s'))
#define k(u) St[u].k
#define s(u) St[u].s
#define a(u) St[u].a
#define o(u) St[u].o
#define son(u) St[u].son
#define str(u) St[u].String
using namespace std;
								
inline int read(){
	int f = 1 , k = 0 ;
	char c = getchar() ;
	while((c < '0') | (c > '9')) { f = (c == '-' ? -1 : 1) ; c = getchar() ;}
	while((c >= '0') & (c <= '9')) { k = (k << 3) + (k << 1) + (c ^ 48) ; c = getchar() ;}
	return f == - 1 ? -k : k ;
}
								
inline string read_s() {
	string s ; char c = getchar() ;
	while(('a' > c) | (c > 'z')) c= getchar() ;
	while((('a' <= c) & (c <= 'z')) | (c == '.')) {
		s += c ;
		c = getchar() ;
	}
	return s ;
}
								
inline char read_c() {
	char c = getchar() ;
	while(('a' > c) | (c > 'z')) c = getchar() ;
	return c ;
}
								
void output(int now){
	if(now < 0){
		putchar('-');
		output(- now);
	}
	else{
		if(now > 9) output(now / 10);
		putchar((now % 10) ^ 48);
	}
}
								
void Out(string now) {
	int num = now.length() - 1;
	for(int i=0 ; i<=num ; i++) putchar(now[i]) ;
	ent ;
	return ;
}
								
struct Type {
	int son[505] , o[505] ;
	string String[505] ;
	int k , s , a ; // k , s , a , o 题目给出 , son 儿子节点编号 String 名字
}St[505];
int s[505] , a[505] , b[505] , f[505] , Cnt = 0 ;
string name[505] ;
map<string , int> ys ; //内存占用 + 映射
								
int Mx(int x , int y) { return x > y ? x : y ;}
int MN(int x , int y) { return x < y ? x : y ;}
								
void Solve_1(int u) {
//	cout << "u = " << u << '\n' ;
	if(! k(u)) return ; o(u)[1] = 0;
	for(int i=2 ; i<=k(u); i++) {
		int last = o(u)[i - 1] + s(son(u)[i - 1]) , pos = last ;
//		output(last) , spc , output(pos) , ent ;
		for(int j=last ; j<=last+a(son(u)[i]) ; j++) {
			if(!(j % a(son(u)[i]))) {
				pos = j ;
				break ;
			}
		}
		o(u)[i] = pos ;
	}
	int last = o(u)[k(u)] + s(son(u)[k(u)]) , pos = last ;
	for(int j=last ; j<=last+a(u) ; j++) {
		if(!(j % a(u))) {
			pos = j ;
			break ;
		}
	}
	s(u) = pos ;
}
								
void insert(string now , int u , int v) { // name u val
	++ k(u) ;
	a(u) = Mx(a(u) , a(v)) ;
	son(u)[k(u)] = v ;
	str(u)[k(u)] = now ;
}
								
void insert_(string now , int num) { // name u
	name[++ Cnt] = now ;
	f[Cnt] = num , s[Cnt] = s(num) , a[Cnt] = a(num) ;
	int last = b[Cnt - 1] + s[Cnt - 1] , pos = last ;
	for(int j=last ; j<=last+a[Cnt] ; j++) {
		if(!(j % a[Cnt])) {
			pos = j ;
			break ;
		}
	}
	b[Cnt] = pos ;
}
								
int find(int u , string now) {
	string first , second ; int num = 0 , pos = 0 , len = (int)now.length() - 1;
	while(now[num] != '.' && num <= len) { first += now[num] , ++ num ;} num ++;
	while(num <= len) {second += now[num] , ++ num ;}
	for(int i=1 ; i<=k(u) ; i++) {
		if(str(u)[i] == first) { pos = i ; break ;}
	}
	int v = son(u)[pos] , val = o(u)[pos] ;
	return second.empty() ? val : val + find(v , second) ;
}
								
string fs(int u , int x) {
	if(! k(u)) return "" ;
	int pos = 0 ;
	for(int i=1 ; i<=k(u) ; i++) {
		if((o(u)[i] <= x) & (x < o(u)[i] + s(son(u)[i]))) { pos = i ; break ;}
	}
	if(! pos) return "ERR" ;
	string ans = fs(son(u)[pos] , x - o(u)[pos]) ;
	return ans != "ERR" ? ans != "" ? str(u)[pos] + "." + ans : str(u)[pos] : "ERR";
}
								
void run_1() {
	string of = read_s() ; int k = read() ;
	ys[of] = ++ Cnt ;
	for(int i=1 ; i<=k ; i++) {
		string c = read_s() , now = read_s() ;
		insert(now , Cnt , ys[c]) ;
	}
	Solve_1(Cnt) ;
	output(s(Cnt)) , spc , output(a(Cnt)) , ent ;	
}
								
void run_2() {
	string c = read_s() , now = read_s() ;
	insert_(now , ys[c]) ;
	output(b[Cnt]) , ent ;
}
								
void run_3() {
	string now = read_s() , first , second ; int num = 0 , pos = 0 , len = (int)now.length() - 1 ;
//	cout << now << '\n' ;
	while(now[num] != '.' && num <= len) { first += now[num] , ++ num ;} num ++;
	while(num <= len) {second += now[num] , ++ num ;}
	for(int i=1 ; i<=Cnt ; i++) {
		if(name[i] == first) { pos = i ; break ;}
	}
//	cout << first << ' ' << second << ' ' << now << ' ' << pos << '\n' ;
	output(second.empty() ? b[pos] : b[pos] + find(f[pos] , second)) , ent ;
}
								
void run_4() {
	int k = read() , pos = 0 ;
	for(int i=1 ; i<=Cnt ; i++) {
		if(b[i] <= k && k < b[i] + s[i]) {
			pos = i ;
			break ;
		}
	}
	if(! pos) { return puts("ERR") , (void)0 ;}
	string now = name[pos] , ans = fs(f[pos] , k - b[pos]) ;
	return Out(ans != "ERR" ? ans != "" ? name[pos] + "." + ans : name[pos] : "ERR") , (void)0 ;
}
								
void init() {
	Cnt = 4 ;
	for(int i=1 ; i<=4 ; i++) s(i) = a(i) = (1 << (i - 1)) ;
	ys["byte"] = 1 ; ys["short"] = 2 ; ys["int"] = 3 ; ys["long"] = 4 ;
}
								
signed main() {
	int T = read() ; init() ;
	while(T --) {
		int opt = read() ;
		if(opt == 1) run_1() ;
		if(opt == 2) run_2() ;
		if(opt == 3) run_3() ;
		if(opt == 4) run_4() ;
	}
	return 0 ;
}

CSP-S 2023T4种树

这道题目赛时切出来那确实有亿点实力,这道题目正解是二分答案。

二分答案出最少需要的天数,然后取维护看是否符合所有条件。

总分:\(100 + 100 + 45 + 0 = 245\)

CSP-S 2022

CSP-S 2022 T1假期计划
本题可以直接用 \(\Omicron(n^2)\) 的暴力通过,我们可以考虑枚举 \(B,C\) 然后在考虑 \(A,D\) 我们只需要枚举每个点满足题目条件能造成最大价值的三个点去维护。

Code
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <queue>
#include <map>
#include <set>
#define prt printf
#define ll long long
#define int long long
#define spc putchar(' ')
#define ent putchar('\n')
#define pr_ prt("---")
#define prx prt("***")
#define prtn (putchar('N') , putchar('o'))
#define prty (putchar('Y') , putchar('e') , putchar('s'))
using namespace std;

inline int read(){
	int f = 1 , k = 0 ;
	char c = getchar() ;
	while((c < '0') | (c > '9')) { f = (c == '-' ? -1 : 1) ; c = getchar() ;}
	while((c >= '0') & (c <= '9')) { k = (k << 3) + (k << 1) + (c ^ 48) ; c = getchar() ;}
	return f == - 1 ? -k : k ;
}

void output(int now){
	if(now < 0){
		putchar('-');
		output(- now);
	}
	else{
		if(now > 9) output(now / 10);
		putchar((now % 10) ^ 48);
	}
}

const int maxn = 25e2 + 1 , maxm = 1e4 + 1 , INF = 4e18;
int n , m , k , ans = -INF;
int dis[maxn][maxn] , d[maxn] , f[maxn][maxn] , pos[maxn][4];
int h[maxn] , cnt = 0 ; // edge ->
struct Edge{
	int next , to ;
}e[maxm << 1];

inline void add(int u , int v) { e[++ cnt] = {h[u] , v} ; h[u] = cnt ; }
inline void Mx(int &a , int b) { a = a > b ? a : b ;}

void Bfs(int s) { //Run the shortest path for each point
	dis[s][s] = 0 ; queue<int> q ; q.push(s) ;
	while(! q.empty()) {
		int u = q.front() ; q.pop() ;
		for(int i=h[u] ; i ; i=e[i].next) {
			int v = e[i].to ;
			if(dis[s][v] == INF) {dis[s][v] = dis[s][u] + 1 ; q.push(v) ;} 
		}
	}
}

signed main() {
	n = read() , m = read() , k = read() + 1;
	for(int i=2 ; i<=n ; i++) d[i] = read() ;
	for(int i=1 ; i<=m ; i++) { int u = read() , v = read() ; add(u , v) ; add(v , u) ; }
	for(int i=1 ; i<=n ; i++) {
		for(int j=1 ; j<=n ; j++) dis[i][j] = INF ;
	}
	for(int i=1 ; i<=n ; i++) Bfs(i) ;
	for(int i=1 ; i<=n ; i++) {
		for(int j=1 ; j<=n ; j++) {if((i != j) & (dis[1][i] <= k) & (dis[i][j] <= k)) f[i][j] = d[i] + d[j] ; else f[i][j] = -INF ;}
	}
	for(int i=2 ; i<=n ; i++) { // 考虑维护到每个点最近的三个点 ,避免贪心错误
		pos[i][1] = pos[i][2] = pos[i][3] = i ;
		for(int j=2 ; j<=n ; j++) {
			if(f[pos[i][1]][i] < f[j][i]) pos[i][3] = pos[i][2] , pos[i][2] = pos[i][1] , pos[i][1] = j ;
			else if(f[pos[i][2]][i] < f[j][i]) pos[i][3] = pos[i][2] , pos[i][2] = j ;
			else if(f[pos[i][3]][i] < f[j][i]) pos[i][3] = j ;
		}
	}
	for(int i=2 ; i<=n ; i++) {
		for(int j=2 ; j<=n ; j++) {
			if((i != j) & (dis[i][j] <= k)) {
				for(int x=1 ; x<=3 ; x++) { // pos_i
					for(int y=1 ; y<=3 ; y++) { // pos_j 
						if((pos[i][x] != j) & (pos[j][y] != i) & (pos[i][x] != pos[j][y])) {Mx(ans , f[pos[i][x]][i] + f[pos[j][y]][j]) ; break ;}
					}
				}
			}
		}
	}
	return output(ans) , ent , 0 ;
}

CSP-S 2022 T2策略游戏
直接贪心考虑所有方案,然后用RMQ等算法去维护。

Code
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <queue>
#include <map>
#include <set>
#define prt printf
#define ll long long
#define int long long
#define spc putchar(' ')
#define ent putchar('\n')
#define pr_ prt("---")
#define prx prt("***")
#define prtn (putchar('N') , putchar('o'))
#define prty (putchar('Y') , putchar('e') , putchar('s'))
using namespace std;

inline int read(){
	int f = 1 , k = 0 ;
	char c = getchar() ;
	while((c < '0') | (c > '9')) { f = (c == '-' ? -1 : 1) ; c = getchar() ;}
	while((c >= '0') & (c <= '9')) { k = (k << 3) + (k << 1) + (c ^ 48) ; c = getchar() ;}
	return f == - 1 ? -k : k ;
}

void output(int now){
	if(now < 0){
		putchar('-');
		output(- now);
	}
	else{
		if(now > 9) output(now / 10);
		putchar((now % 10) ^ 48);
	}
}

const int maxn = 4e5 + 1;
int Maxa[maxn][21] , Mina[maxn][21] , Maxb[maxn][21] , Minb[maxn][21] , fMax[maxn][21] , fMin[maxn][21] , a[maxn] , b[maxn];
int n , m , q ;

int Mx(int a , int b) { return a > b ? a : b ;}
int Mn(int a , int b) { return a < b ? a : b ;}

void init() {
	for(int i=1 ; i<Mx(n,m) ; i++) {
		for(int j=0 ; i+(1<<j)-1<=Mx(n,m) ; j++) Maxa[i][j] = Maxb[i][j] = fMax[i][j] = -1e18 , Mina[i][j] = Minb[i][j] = fMin[i][j] = 1e18 ; 
	}	
}

int q_max(int l , int r) {
	int k = log2(r - l + 1) ;
	return Mx(Maxa[l][k] , Maxa[r - (1 << k) + 1][k]) ;
}

int q_min(int l , int r) {
	int k = log2(r - l + 1) ;
	return Mn(Mina[l][k] , Mina[r - (1 << k) + 1][k]) ;
}

int q_fmax(int l , int r) {
	int k = log2(r - l + 1) ;
	return Mx(fMax[l][k] , fMax[r - (1 << k) + 1][k]) ;
}

int q_zmin(int l , int r) {
	int k = log2(r - l + 1) ;
	return Mn(fMin[l][k] , fMin[r - (1 << k) + 1][k]) ;
}

int Max(int l , int r) {
	int k = log2(r - l + 1) ;
	return Mx(Maxb[l][k] , Maxb[r - (1 << k) + 1][k]) ;
}

int Min(int l , int r) {
	int k = log2(r - l + 1) ;
	return Mn(Minb[l][k] , Minb[r - (1 << k) + 1][k]) ;
}

signed main(){
	n = read() , m = read() , q = read() ; init() ;
	for(int i=1 ; i<=n ; i++) {a[i] = read() , Maxa[i][0] = a[i] , Mina[i][0] = a[i] ; if(a[i] < 0) fMax[i][0] = a[i] ; else fMin[i][0] = a[i] ;}
	for(int i=1 ; i<=m ; i++) {b[i] = read() , Maxb[i][0] = b[i] , Minb[i][0] = b[i] ;}
	for(int j=1 ; (1<<j)<=n ; j++) {
		for(int i=1 ; i+(1<<j)-1<=n ; i++) {
			Maxa[i][j] = Mx(Maxa[i][j - 1] , Maxa[i + (1 << (j - 1))][j - 1]) ;
			Mina[i][j] = Mn(Mina[i][j - 1] , Mina[i + (1 << (j - 1))][j - 1]) ;
			fMax[i][j] = Mx(fMax[i][j - 1] , fMax[i + (1 << (j - 1))][j - 1]) ;
			fMin[i][j] = Mn(fMin[i][j - 1] , fMin[i + (1 << (j - 1))][j - 1]) ;
//			output(i) , spc , output(i - 1 + (1 << j)) , ent ;
//			output(Maxa[i][j]) , spc , output(Mina[i][j]) , spc , output(fMax[i][j]) , spc , output(fMin[i][j]) , ent ;
		}
	}
	for(int j=1 ; (1<<j)<=m ; j++) {
		for(int i=1 ; i+(1<<j)-1<=m ; i++) {
			Maxb[i][j] = Mx(Maxb[i][j - 1] , Maxb[i + (1 << (j - 1))][j - 1]) ;
			Minb[i][j] = Mn(Minb[i][j - 1] , Minb[i + (1 << (j - 1))][j - 1]) ;
		}
	}
	while(q --) {
		int l0 = read() , r0 = read() , l1 = read() , r1 = read() , ans = -1e18;
		int maxb = Max(l1 , r1) , minb = Min(l1 , r1) ; /*output(maxb) , spc , output(minb) , ent ;*/
		int f1 = q_max(l0 , r0) ; if(f1 >= 0) ans = Mx(ans , f1 * minb) ; else ans = Mx(ans , f1 * maxb) ;
		int f2 = q_min(l0 , r0) ; if(f2 >= 0) ans = Mx(ans , f2 * minb) ; else ans = Mx(ans , f2 * maxb) ;
		int f3 = q_fmax(l0 , r0) ; if(f3 < 0 && f3 != -1e18) ans = Mx(ans , f3 * maxb) ;
		int f4 = q_zmin(l0 , r0) ; if(f4 >= 0 && f4 != 1e18) ans = Mx(ans , f4 * minb) ;
		output(ans) , ent ;
	}
	return 0;
}
/*
x≥0 时,B 最小 𝑦
x<0 时,B 最大 y

x≥0,那么 B 最小 y
y≥0,那么 A 最大 x
y<0,那么 A 最小非负数 x
x<0,那么 B 最大 y。
y≥0,那么 A 最大负数 x
y<0,那么 A 最小 x。

A 的四种:最大 x;最小 x,最大负数 x,最小非负数 x。答案Max。
*/

CSP-S 2022 T3星战
这道题目整解是一个很好写的哈希,但是赛事没有想出所以 \(40 + 10 + 10 + 15\)(输出No) \(= 75\)

CSP-S 2022 T4数据传输:
没有想到正解所以打了 \(16\) 特殊数据的分数。

Code
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <queue>
#include <map>
#include <set>
#define prt printf
#define ll long long
#define int long long
#define spc putchar(' ')
#define ent putchar('\n')
#define pr_ prt("---")
#define prx prt("***")
#define prtn (putchar('N') , putchar('o'))
#define prty (putchar('Y') , putchar('e') , putchar('s'))
using namespace std;

inline int read(){
	int f = 1 , k = 0 ;
	char c = getchar() ;
	while((c < '0') | (c > '9')) { f = (c == '-' ? -1 : 1) ; c = getchar() ;}
	while((c >= '0') & (c <= '9')) { k = (k << 3) + (k << 1) + (c ^ 48) ; c = getchar() ;}
	return f == - 1 ? -k : k ;
}

void output(int now){
	if(now < 0){
		putchar('-');
		output(- now);
	}
	else{
		if(now > 9) output(now / 10);
		putchar((now % 10) ^ 48);
	}
}

const int maxn = 2e5 + 1;
int h[maxn] , cnt = 0 , d[maxn] , anc[maxn][31] , a[maxn] , n , k , q , dis[maxn];
struct Edge{
	int next , to;
}e[maxn << 1] ;

void add(int u , int v) { e[++ cnt] = {h[u] , v} ; h[u] = cnt ; return ;}

int mn(int a , int b) { return a < b ? a : b ;}

void dfs(int u , int fa , int num){
	dis[u] = num ;
	d[u] = d[fa] + 1 , anc[u][0] = fa;
	for(int i=1 ; (1<<i)<=d[u] ; i++) anc[u][i] = anc[anc[u][i - 1]][i - 1];
	for(int i=h[u] ; i ; i=e[i].next){
		int v = e[i].to ;
		if(v == fa) continue ;
		dfs(v , u , num + a[v]) ;
	}
}

int lca(int a , int b){
	if(d[a] < d[b]) swap(a , b) ; 	
	int k = log2(d[a])/log(2) ; 
	for(int i=k ; i>=0 ; i--){
		if(d[a] - (1 << i) >= d[b]) a = anc[a][i] ;
	}
	if(a == b) return b ;
	for(int i=k ; i>=0 ; i--){
		if(anc[a][i] != 0 && anc[a][i] != anc[b][i]) { a = anc[a][i] , b = anc[b][i] ;}
	}
	return anc[a][0] ;
}

signed main(){
	n = read() , q = read() , k = read() ;
	if(k <= 1) { // subtask_1 k = 1 , LCa 
		for(int i=1 ; i<=n ; i++) a[i] = read() ;
		for(int i=1 ; i<n ; i++) {
			int u = read() , v = read() ;
			add(u , v) , add(v , u) ;
		}
		dfs(1 , 1 , a[1]) ;
		while(q --) {
			int A = read() , B = read() ;
			int o = lca(A , B) ;
			output(dis[A] + dis[B] - 2 * dis[o] + a[o]) , ent ;
		}
	}
	return 0;
}
/*
7 3 1
1 2 3 4 5 6 7
1 2
1 3
2 4
2 5
3 6
3 7
4 7
5 6
1 2
*/

总分:\(100 + 100 + 75 + 16 = 291\)

CSP-S 2021

CSP-S 2021 T1桥梁分配
一个很简单的题目,枚举第 \(i\) 个机场有几个飞机能产生贡献,然后用 set 维护。

Code
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <vector>
#include <queue>
#include <map>
#include <set>
#define prt printf
#define ll long long
//#define int long long
#define spc putchar(' ')
#define ent putchar('\n')
#define pr_ prt("---")
#define prx prt("***")
#define prtn (putchar('N') , putchar('o'))
#define prty (putchar('Y') , putchar('e') , putchar('s'))
using namespace std;

inline int read(){
	int f = 1 , k = 0 ;
	char c = getchar() ;
	while((c < '0') | (c > '9')) { f = (c == '-' ? -1 : 1) ; c = getchar() ;}
	while((c >= '0') & (c <= '9')) { k = (k << 3) + (k << 1) + (c ^ 48) ; c = getchar() ;}
	return f == - 1 ? -k : k ;
}

void output(int now){
	if(now < 0){
		putchar('-');
		output(- now);
	}
	else{
		if(now > 9) output(now / 10);
		putchar((now % 10) ^ 48);
	}
}

const int maxn = 1e5 + 1;

int n , m_1 , m_2 , fc[maxn] , fw[maxn] , ans = -2e9;
set<pair<int , int>> q , p;

int mx(int a , int b) { return a > b ? a : b ;}

signed main(){
	n = read() , m_1 = read() , m_2 = read() ;
	for(int i=1 ; i<=m_1 ; i++) {int s = read() , e = read() ; q.insert({s , e}) ;};
	for(int i=1 ; i<=n ; i++) { int pos = 0 , cnt = 0 ; auto u = q.lower_bound({pos , 0}) ; while(u != q.end()) { pos = u -> second ; q.erase(u) ; ++ cnt ; u = q.lower_bound({pos , 0}) ;} fc[i] = fc[i - 1] + cnt ;}
	for(int i=1 ; i<=m_2 ; i++) {int s = read() , e = read() ; p.insert({s , e}) ;};
	for(int i=1 ; i<=n ; i++) { int pos = 0 , cnt = 0 ; auto u = p.lower_bound({pos , 0}) ; while(u != p.end()) { pos = u -> second ; p.erase(u) ; ++ cnt ; u = p.lower_bound({pos , 0}) ;} fw[i] = fw[i - 1] + cnt ; ans = mx(ans , fw[i] + fc[n - i]) ;}
	return output(mx(ans , fc[n])) , ent , 0 ;
}

CSP-S 2021 T2 括号分配
这道题目想出状态就很简单了,具体看代码。

Code
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <queue>
#include <map>
#include <set>
#define prt printf
#define ll long long
#define int long long
#define spc putchar(' ')
#define ent putchar('\n')
#define pr_ prt("---")
#define prx prt("***")
#define prtn (putchar('N') , putchar('o'))
#define prty (putchar('Y') , putchar('e') , putchar('s'))
using namespace std;

inline int read(){
	int f = 1 , k = 0 ;
	char c = getchar() ;
	while((c < '0') | (c > '9')) { f = (c == '-' ? -1 : 1) ; c = getchar() ;}
	while((c >= '0') & (c <= '9')) { k = (k << 3) + (k << 1) + (c ^ 48) ; c = getchar() ;}
	return f == - 1 ? -k : k ;
}

void output(int now){
	if(now < 0){
		putchar('-');
		output(- now);
	}
	else{
		if(now > 9) output(now / 10);
		putchar((now % 10) ^ 48);
	}
}

const int maxn = 5e2 + 1 ;
const int mod = 1e9 + 7 ;
int f[maxn][maxn][6] , n , k ;
char s[maxn] ;

bool check(int i , int j) { return ((s[i] == '(') | (s[i] == '?')) & ((s[j] == ')') | (s[j] == '?')) ;}

signed main(){
	n = read() , k = read() ;
	for(int i=1 ; i<=n ; i++) {while((s[i] != '?') & (s[i] != '(') & (s[i] != ')') & (s[i] != '*')) s[i] = getchar() ; f[i][i - 1][0] = 1 ;}
	for(int len=1 ; len<=n ; len++) {
		for(int l=1 ; l<=n-len+1 ; l++) {
			int r = l + len - 1;
			f[l][r][0] = (k >= len) & ((s[r] == '*') | (s[r] == '?')) ? f[l][r - 1][0] : 0 ;
			if(len >= 2) {
				if(check(l , r) == true) f[l][r][5] = (f[l + 1][r - 1][0] + f[l + 1][r - 1][1] + f[l + 1][r - 1][2] + f[l + 1][r - 1][3]) % mod ;
				for(int i=l ; i<r ; i++) {
					f[l][r][1] = (f[l][r][1] + (f[l][i][1] + f[l][i][4]) * f[i + 1][r][5]) % mod;
					f[l][r][2] = (f[l][r][2] + (f[l][i][3] + f[l][i][2]) * f[i + 1][r][5]) % mod;
					f[l][r][3] = (f[l][r][3] + f[l][i][2] * f[i + 1][r][0]) % mod;
					f[l][r][4] = (f[l][r][4] + f[l][i][1] * f[i+1][r][0]) % mod;
				}
			}
			f[l][r][4] = (f[l][r][4] + f[l][r][0]) % mod;
			f[l][r][2] = (f[l][r][2] + f[l][r][5]) % mod;
		}
	}
	return output(f[1][n][2]) , ent , 0;
}
/*
区间 f i j k $ i ~ j $ 状态为 k 的方案数, 0 : *cap* 1 : *cap) 2 : (cap) 3 :(cap*  4 : *cap* 5 : (cap) 0 4 来维护* \leq k
*/

CSP-S 2021 T3回文
一个爆搜,爆搜的时候维护字符串。

Code
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <queue>
#include <map>
#include <set>
#define prt printf
//#define ll long long
#define int long long
#define spc putchar(' ')
#define ent putchar('\n')
#define pr_ prt("---")
#define prx prt("***")
#define prtn (putchar('N') , putchar('o'))
#define prty (putchar('Y') , putchar('e') , putchar('s'))
using namespace std;

inline int read(){
	int f = 1 , k = 0 ;
	char c = getchar() ;
	while((c < '0') | (c > '9')) { f = (c == '-' ? -1 : 1) ; c = getchar() ;}
	while((c >= '0') & (c <= '9')) { k = (k << 3) + (k << 1) + (c ^ 48) ; c = getchar() ;}
	return f == - 1 ? -k : k ;
}

void output(int now){
	if(now < 0){
		putchar('-');
		output(- now);
	}
	else{
		if(now > 9) output(now / 10);
		putchar((now % 10) ^ 48);
	}
}
/*
考虑匹配数字两个数组 l_1 = i , 代表 i 第一次出现的下标 , r_1 = i 代表 i 出现了多次且出现最后一次的下标
*/
const int maxn = 5e5 + 1;
int n , a[maxn << 1] , l_1[maxn << 1] , r_1[maxn << 1] ;
char ans[maxn << 1] ;

void init() {
	memset(l_1 , 0 , sizeof l_1) ;
	memset(r_1 , 0 , sizeof r_1) ;
//	memset(ans , 0 , sizeof ans) ;
	n = read() << 1; for(int i=1 ; i<=n ; i++) { a[i] = read() ; l_1[a[i]] ? r_1[a[i]] = i : l_1[a[i]] = i ;}
//	for(int i=1 ; i<=n ; i++) output(l_1[i]) , spc , output(r_1[i]) , ent ;
}

bool solve(int x) {
	memset(ans , 0 , sizeof ans) ;
	int ll = 0 , lr = n + 1 , rl = x == 1 ? r_1[a[x]] : l_1[a[x]] , rr = x == 1 ? r_1[a[x]] : l_1[a[x]] , cnt = 1 ;
	ans[1] = x == 1 ? 'L' : 'R' ;
	ans[n] = 'L' ; 
	x == 1 ? ++ ll : -- lr ;
	while((cnt << 1) < n) {
//		output(ll) , spc , output(lr) , spc , output(rl) , spc , output(rr) , ent;
		if(ll < rl) {
//			output(11) , ent ;
			if(r_1[a[ll + 1]] - 1 == rr) {
//				output(1) , ent ;
				++ ll , ++ rr ; 
				ans[++ cnt] = 'L' ;
				ans[n - cnt + 1] = 'R' ;
				continue ;
			}
			else if(r_1[a[ll + 1]] + 1 == rl) {
//				output(2) , ent ;
				++ ll , -- rl ; 
				ans[++ cnt] = 'L' ;
				ans[n - cnt + 1] = 'L' ;
				continue ;
			}
		}
		if(lr > rr) {
//			output(22) , ent ;
			if(l_1[a[lr - 1]] - 1 == rr) {
//				output(3) , ent ;
				-- lr , ++ rr ;
				ans[++ cnt] = 'R' ;
				ans[n - cnt + 1] = 'R' ;
				continue ;
			}
			else if(l_1[a[lr - 1]] + 1 == rl) {
//				output(4) , ent ;
				-- lr , -- rl ;
				ans[++ cnt] = 'R' ;
				ans[n - cnt + 1] = 'L' ;
				continue ;
			}
		}
		return false ;
	}
	return true ;
}

void OUT() { for(int i=1 ; i<=n ; i++) { putchar(ans[i]) ;} /*ent ;*/}

signed main() {
	int T = read() ; while(T --) { init() ; solve(1) ? OUT() : solve(n) ? OUT() : output(-1) , ent ; }
	return 0 ;
}

CSP-S 2021 T4交通规划
没看不会。

总分:\(100 + 100 + 100 + 0 = 300\)

CSP-S 2020

CSP-2020 T1
大模拟,没有什么好说的写炸了。

Code
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <queue>
#include <map>
#include <set>
#define prt printf
#define ll long long
#define int long long
#define spc putchar(' ')
#define ent putchar('\n')
#define pr_ prt("---")
#define prx prt("***")
#define prtn (putchar('N') , putchar('o'))
#define prty (putchar('Y') , putchar('e') , putchar('s'))
using namespace std;

int read(){
	int f = 1 , k = 0;
	char c = getchar();
	while(c < '0' || c > '9'){
		if(c == '-') f = -1;
		c = getchar() ;
	}
	while(c >= '0' && c <= '9'){
		k = (k << 3) + (k << 1) + (c ^ 48);
		c = getchar() ;
	}
	return (f == 1 ? k : -k);
}

void output(int now){
	if(now < 0){
		putchar('-');
		output(- now);
	}
	else{
		if(now > 9) output(now / 10);
		putchar((now % 10) ^ 48);
	}
}

const int y[] = {0 , 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31};
const int ry[] = {0 , 31 , 29 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31};

void solve(){
	int n = read() ;
	if(n <= 1721423){
		int num = (n / 1461) ; num = num * 4 ; n %= 1461 ;
		if(n >= 366) ++ num , n -= 366 , num += n / 365 , n %= 365 ;
		if(! (num % 4)){
			int i = 1 ; while(n >= ry[i]) { n -= ry[i] , ++ i ;}
			output(1 + n) , spc , output(i) , spc , output(4713 - num) , spc , putchar('B') , putchar('C') , ent ;
		}
		else{
			int i = 1 ; while(n >= y[i]) { n -= y[i] , ++ i ;}
			output(1 + n) , spc , output(i) , spc , output(4713 - num) , spc , putchar('B') , putchar('C') , ent ;
		}
	}
	else if(n <= 2299160){
		n -= 1721424 ; int num = 1 + 4 * (n / 1461) ; n %= 1461 ;
//		int num = n / 146097 ; n %= 146097 ;
//		num *= 400 ; num += (n / 36524) * 100 ; n %= 36524 ; 
		if(n < 1461 - 366) { num += n / 365 , n %= 365 ; int i = 1 ; while(n >= y[i]) { n -= y[i] , ++ i ;} output(n + 1) , spc , output(i) , spc , output(num) , spc , ent ; return ;}
		num += 3 ; int i = 1 ; while(n >= ry[i]) { n -= ry[i] , ++ i ;} output(n + 1) , spc , output(i) , spc , output(num + 1) , spc , ent ; return ;
	}
	else {
		if(n < 2299238) {}
	}
}

signed main(){
	int T = read() ;
	while(T --) solve() ;
	return 0 ;
}

CSP-S 2020 T2动物园
莫名奇妙的错误,一个贪心。

Code
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <queue>
#include <map>
#include <set>
#define prt printf
#define ll long long
#define int __int128
#define spc putchar(' ')
#define ent putchar('\n')
#define pr_ prt("---")
#define prx prt("***")
#define prtn (putchar('N') , putchar('o'))
#define prty (putchar('Y') , putchar('e') , putchar('s'))
using namespace std;

int read(){
	int f = 1 , k = 0;
	char c = getchar();
	while(c < '0' || c > '9'){
		if(c == '-') f = -1;
		c = getchar() ;
	}
	while(c >= '0' && c <= '9'){
		k = (k << 3) + (k << 1) + (c ^ 48);
		c = getchar() ;
	}
	return (f == 1 ? k : -k);
}

void output(int now){
	if(now < 0){
		putchar('-');
		output(- now);
	}
	else{
		if(now > 9) output(now / 10);
		putchar((now % 10) ^ 48);
	}
}

int a , b , flag = 1 ;

//int Xor(int a , int b){
//	int res = 0 , i = 0;
//	if(a < b) swap(a , b) ;
//	while(a){
//		if((a & 1) | (b & 1)) res += (1 << i) ;
//		a >>= 1 , b >>= 1 , ++ i;
//	}
//	return res ;
//}

//void OT() {putchar('1') , putchar('8') , putchar('4') , putchar('4') , putchar('6') , putchar('7') , putchar('4') , putchar('4') , putchar('0') , putchar('7') , putchar('3') , putchar('7') , putchar('0') , putchar('9') , putchar('5') , putchar('5') , putchar('1') , putchar('6') , putchar('1') , putchar('6') ; return ;}

signed main(){
	int n = read() , m = read() , c = read() , k = read() ;
	for(int i=1 ; i<=n ; i++) {int x = read() ; a |= x ; /*Xor(a , x) ;*/}
	for(int i=1 ; i<=m ; i++) {int x = read() ; b |= (1 << x) ; /*Xor(b , x) ;*/ x = read() ;} /*Xor(a , ~b) ;*/ a |= ~b ;
	for(int i=1 ; i<=k ; i++) {flag <<= ((a >> (i - 1)) & 1) ;}
	if(! flag && ! n) { /*cout << "184" << "467" << "4407" << "370" << "9551" << "616‬"*/ printf("18446744073709551616") ; return 0 ;}
	else return output(flag - n) , ent , 0 ;
}

CSP-S 2020 T3函数调用
没有写,当天状态不好。

CSP-S 2020 T4贪吃蛇
没有写,当天状态不好。

总分:\(40 + 75 = 135\)

对于这几场 \(CSP-S\) 的一些总结:
感觉 CCF 有很大的可能会考: 模拟(蓝/绿) + 图论 (蓝) + 思维(绿/黄) + 蓝/紫。
而且 CCF 更偏向于出思维难度很高的题目,代码特别难的题目挺少。
分数的瑞平:由于 CCF 近些年 S 组的难度一直递增所以可能会考的越来越低 \(\to 0\) /cf,所以我上考场一般不想正解,写一个暴力的 subtask + 部分分 subtask + 骗分 subtask ,所有题目按难度排序大致成绩为 \(85 + 65 + 65 + 45 = 260\)(说实话这个分很高,但是我们认真对待考试,只要打暴力(不是完全模拟),基本都有一等)

暑假自评

首先对于:

  • DP
  • 莫队
  • RMQ
  • FHQ
  • Trie
  • CDQ 分治
  • 2-SAT
  • 博弈论
  • 差分约束
  • Prim
    等许多算法掌握不精通不能轻松刷紫/黑

还有对于某些没有想出正解且不愿意看文字题解,所以进行了 \(KMP\) 操作。

所以 \(2024\) 暑假集训/学习 \(\to\) 祭。

建议:拒绝代码题解,不要因为没有题解所以做不出普及组的题,不然平时刷题全是蓝、紫,考试考的时候只会红、橙。
推荐: CaoSheng 暑假集训游祭

posted @ 2024-08-24 10:04  CaoSheng  阅读(48)  评论(1)    收藏  举报