1. 程式人生 > 實用技巧 >2020CSP-S反思

2020CSP-S反思

目錄

儒略日

題目

傳送門

思路

毫無思路

反思

非常麻煩的一道題,居然還是第一題!!!看了好久題目感覺做不出來,半個小時就放棄了(還好放棄了)

雖然及時放棄了這道題,但是也浪費了半個小時(不然第二題的錯誤可能就查出來了),以後還是要多注意時間

動物園

題目

傳送門

思路

其實不難的一道題(但是目前還不知道為什麼會WA)

其實這題很多東西都是迷惑人的,關鍵是要理解題目

比如說飼料的種類,題目有這麼一句話:

資料保證所有 ai 互不相同,所有的 qi 互不相同。

這就意味著q陣列連離散化都不需要,q直接賦值為當前下標即可

其他部分細節&優化程式碼見

關於輸出2^64溢位的問題:其實已經想到了這個,但是畢竟大樣例都沒過,就不管了

反思

  1. 要仔細理解題目,發現一些細節的東西
  2. 多注意細節(如unsigned long long(還好沒掉坑裡),特判等)

其實當時已經打好對拍並得到了出錯資料,但是時間問題就沒有再仔細除錯,還是要多注意時間安排

程式碼

考場(40分)

#include <iostream>
#include <cstdio>
#include <algorithm>
#define nn 1000010
#define ll unsigned long long
using namespace std;
ll read() {
	ll re = 0 , sig = 1;
	char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-')sig = -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9') {
		re = (re << 1) + (re << 3) + c - '0';
		c = getchar();
	}
	return re * sig;
}
int n , m , c , k;
ll a[nn];
bool buy[nn];
int p[nn] , q[nn];
int main() {
//	freopen("zoo.in" , "r" , stdin);
//	freopen("zoo.out" , "w" , stdout);
	scanf("%d %d %d %d" , &n , &m , &c , &k);
//	printf("%d %d %d %d\n" , n , m , c , k);
	ll pus = 0 , pus2 = 0;
	for(int i = 1 ; i <= n ; i++) {
		a[i] = read();
//		printf("%d " , a[i]);
		pus |= a[i];
	}
//	putchar('\n');
	for(int i = 1 ; i <= m ; i++) {
		p[i] = read(),	q[i] = read();
//		printf("%d %d\n" , p[i] , q[i]);
		q[i] = i;
		pus2 |= (1 << p[i]);
		if((pus >> p[i]) & 1)
			buy[i] = true;
	}
	
	
	ll check = 0;
	ll cnt = 0;
	for(int i = 1 ; i <= m ; i++) {
		if(!buy[i]) {
			check |= (1 << p[i]) , cnt++;
		}
	}
	check ^= (unsigned)-1ll;
	
	int ans = 0;
	if(k <= 20) {
		for(ll i = 0 ; i <= (1 << k) - 1 ; i++) {
			if((i | check) == check)
				ans++;
		}
	}
	else ans = (1 << k) - ((1 << cnt) - 1) * (1 << (k - cnt));
	cout << ans - n;
	return 0;
}

第二版(60分)

#include <iostream>
#include <cstdio>
#include <algorithm>
#define nn 1000010
#define ll unsigned long long
using namespace std;
ll read() {
	ll re = 0 , sig = 1;
	char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-')sig = -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9') {
		re = (re << 1) + (re << 3) + c - '0';
		c = getchar();
	}
	return re * sig;
}
int n , m , c , k;
ll a[nn];
bool buy[nn];
int p[nn] , q[nn];
int main() {
//	freopen("zoo3.in" , "r" , stdin);
//	freopen("zoo.out" , "w" , stdout);
	scanf("%d %d %d %d" , &n , &m , &c , &k);
//	printf("%d %d %d %d\n" , n , m , c , k);
	ll pus = 0 , pus2 = 0;
	for(int i = 1 ; i <= n ; i++) {
		a[i] = read();
//		printf("%d " , a[i]);
		pus |= a[i];
	}
//	putchar('\n');
	for(int i = 1 ; i <= m ; i++) {
		p[i] = read(),	q[i] = read();
//		printf("%d %d\n" , p[i] , q[i]);
		q[i] = i;
		pus2 |= (1 << p[i]);
		if((pus >> p[i]) & 1)
			buy[i] = true;
	}
	
	
	ll check = 0;
	ll cnt = 0;
	for(int i = 1 ; i <= m ; i++) {
		if(!buy[i]) {
			if(((check >> p[i]) & 1) == 0)	cnt++;//20分就差在這一個特判
			check |= (1 << p[i]);
		}
	}
	check ^= (unsigned)-1ll;
	
	ll ans = 0;
	if(k <= 20) 
	{
		for(ll i = 0 ; i <= (1 << k) - 1 ; i++) {
			if((i | check) == check)
				ans++;
		}
	}	
		ans = (1ull << k) - ((1ull << cnt) - 1ull) * (1ull << (k - cnt));
	cout << ans - n;
	return 0;
}

函式呼叫

題目

傳送門

思路

直接模擬的做法不難想到

考慮優化

不難想到可以用線段樹處理:用懶標記直接處理第二種情況(每個數乘一個相同值)(O(1)),第一種情況(指定元素加上一個值)直接下傳即可(O(logn)),最後下傳所有懶標記並輸出(O(nlogn))

70分到手

至於100分?好像是拓撲+線段樹?暫時不知道

反思

其實這題70分並不難,但是要對線段樹足夠熟練(不然時間不夠(特別是前面還有一個噁心題)),所以要先把所有題目看完,做一個整體評估再敲程式碼

程式碼(70分)

#include <iostream>
#include <cstdio>
#define nn 1000010
#define ll long long
#define mod 998244353
using namespace std;
int read() {
	int re = 0 , sig = 1;
	char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-')sig = -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9') {
		re = (re << 1) + (re << 3) + c - '0';
		c = getchar();
	}
	return re * sig;
}
int n , m , q;
ll a[nn];
int dat1[nn] ,dat2[nn] , ty[nn];
int top = 0;
int g[nn * 5];

struct node{
	int l , r , ls , rs;
	ll tag;
}tr[nn * 4];
int build(int l , int r) {
	static int top = 1;
	++top;
	int p = top;
	tr[p].l = l , tr[p].r = r;
	tr[p].tag = 1;
	if(l != r) {
		int mid = (l + r) / 2;
		tr[p].ls = build(l , mid);
		tr[p].rs = build(mid + 1 , r);
	}
	else
		tr[p].ls = tr[p].rs = 0;
	return p;
}
void spread(int p) {
	if(tr[p].l == tr[p].r) {
		a[tr[p].l] *= tr[p].tag;
		a[tr[p].l] %= mod;
		tr[p].tag = 1;
		return;
	}
	tr[tr[p].ls].tag *= tr[p].tag;
	tr[tr[p].rs].tag *= tr[p].tag;
	tr[tr[p].ls].tag %= mod;
	tr[tr[p].rs].tag %= mod;
	tr[p].tag = 1;
}
void change(int p , int i , int dat) {
//	cout << tr[p].l << '\t' << tr[p].r << endl;
	spread(p);
	if(tr[p].l == tr[p].r) {
		a[tr[p].l] += dat;
		a[tr[p].l] %= mod;
		return;
	}
	int mid = (tr[p].l + tr[p].r) / 2;
	if(i <= mid)
		change(tr[p].ls , i , dat);
	else
		change(tr[p].rs , i , dat);
}
void GetAns(int p) {
	spread(p);
	if(tr[p].l == tr[p].r)
		return;
	GetAns(tr[p].ls);
	GetAns(tr[p].rs);
}
int root;

void f(int x) {
	if(ty[x] == 1){
		change(root , dat1[x] , dat2[x]);
		return; 
	}
	if(ty[x] == 2) {
		tr[root].tag *= dat1[x]; 
		tr[root].tag %= mod;
		return;
	}
	for(int i = dat1[x] ; i < dat2[x] ; i++)
		f(g[i]);
}
int main() {
//	freopen("call.in" , "r" , stdin);
//	freopen("call.out" , "w" , stdout);
	n = read();
	for(int i = 1 ; i <= n ; i++)
		a[i] = read();
	root = build(1 , n);
	
/*	tr[root].tag *= 2;
	change(root , 1 , 999);
	GetAns(root);
	for(int i = 1 ; i <= n ; i++)
		printf("%d " , a[i]);
	return 0;*/
	
	m = read();
	for(int i = 1 ; i <= m ; i++) {
		ty[i] = read();
		if(ty[i] == 1) {
			dat1[i] = read();	dat2[i] = read();
		}
		else if(ty[i] == 2) {
			dat1[i] = read();
		}
		else {
			int tmp = read();
			dat1[i] = top;
			dat2[i] = tmp + top;
			for(int j = dat1[i] ; j < dat2[i] ; j++)
				g[j] = read();
			top = dat2[i];
		}
	}
	q = read();
	for(int i = 1 ; i <= q ; i++) {
		f(read());
	}
	GetAns(root);
	for(int i = 1 ; i <= n ; i++)
		printf("%d " , a[i]);
	return 0;
}

貪吃蛇

題目

傳送門

思路&反思

原來這是個洛谷黑題

考場也就看了下題目,沒怎麼想,所以沒有思路就是最好的思路

All In All

要先把題目全部看一遍做一個整體評估,在做題,搞不出來的題先放棄,注意安排好時間