2020CSP-S反思
阿新 • • 發佈:2020-11-17
目錄
儒略日
題目
思路
毫無思路
反思
非常麻煩的一道題,居然還是第一題!!!看了好久題目感覺做不出來,半個小時就放棄了(還好放棄了)
雖然及時放棄了這道題,但是也浪費了半個小時(不然第二題的錯誤可能就查出來了),以後還是要多注意時間
動物園
題目
思路
其實不難的一道題(但是目前還不知道為什麼會WA)
其實這題很多東西都是迷惑人的,關鍵是要理解題目
比如說飼料的種類,題目有這麼一句話:
資料保證所有 ai 互不相同,所有的 qi 互不相同。
這就意味著q陣列連離散化都不需要,q直接賦值為當前下標即可
其他部分細節&優化程式碼見
關於輸出2^64溢位的問題:其實已經想到了這個,但是畢竟大樣例都沒過,就不管了
反思
- 要仔細理解題目,發現一些細節的東西
- 多注意細節(如
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
要先把題目全部看一遍做一個整體評估,在做題,搞不出來的題先放棄,注意安排好時間