1. 程式人生 > 其它 >Noip模擬33墊底反思 2021.8.8

Noip模擬33墊底反思 2021.8.8

T1 Hunter T2 Defence T3 Connect

T1 Hunter

考場上沒寫$%p$掛了25分。也是很牛皮,以後打完過了樣例一定要檢查

因為樣例太小了。。。。。。很容易忘記%%%%

正解隨便手模就出來了。

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 const int NN=1e5+5,p=998244353;
 5 int n,w[NN],ans;
 6 inline int qmo(int a){
 7     int ans=1,b=p-2,c=p; a%=c;
 8     while(b){ if(b&1
) ans=(ans*a)%c; b>>=1; a=(a*a)%c; }return ans; 9 } 10 namespace WSN{ 11 inline short main(){ 12 scanf("%lld",&n); for(int i=1;i<=n;i++) scanf("%lld",&w[i]); 13 for(int i=2;i<=n;i++) (ans+=w[i]*qmo((w[1]+w[i])%p)%p)%=p; 14 printf("%lld\n",ans+1); return
0; 15 } 16 } 17 signed main(){return WSN::main();}
View Code

T2 Defence

據說是很水的動態開點權值線段樹板子。。。。。

想到用線段數維護的值,但是不會打動態開點了。。。

資料結構太弱了,碼力太弱了。。。。。決定以後有時間就打資料結構

噁心死自己的那種。。。盯著程式碼望穿秋水的那種。。。

基本思路:

維護的資訊有第一個一的位置,最後一個一的位置,區間內最長的$0$串的長度

每個點開一顆權值線段樹,維護當時使用完法術後的序列資訊

然後$dfs$到葉子節點向上做線段樹合併,在合併的時候統計節點的資訊記錄答案就行了。

真是做過的題也不記得了,這不就是

玫瑰花精嗎????

原來資料結構學習的太不走心了,以後是要背鍋的,前面付出的太少了。。。。

程式碼能力是要一點一點練的,不是想想題看看程式碼就會的,以後一定要多自己碼,唉~

思路是很簡單的,考場上還是可以想到的,但是被自己的碼力限制了,苦惱

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int NN=1e5+5;
 4 int n,m,q,rt[NN],ans[NN];
 5 struct SNOW{int to,next;};SNOW e[NN<<1];int head[NN],rp;
 6 inline void add(int x,int y){e[++rp]=(SNOW){y,head[x]}; head[x]=rp;}
 7 struct SNOWtree{
 8     int seg,ls[NN*40],rs[NN*40];
 9     int pre[NN*40],nxt[NN*40],len[NN*40];
10     inline void pushup(int x){
11         if(!ls[x]){pre[x]=pre[rs[x]]; nxt[x]=nxt[rs[x]]; len[x]=len[rs[x]]; return;}
12         if(!rs[x]){pre[x]=pre[ls[x]]; nxt[x]=nxt[ls[x]]; len[x]=len[ls[x]]; return;}
13         int lenth=pre[rs[x]]-nxt[ls[x]]-1;
14         len[x]=max(lenth,max(len[ls[x]],len[rs[x]]));
15         pre[x]=min(pre[ls[x]],pre[rs[x]]);
16         nxt[x]=max(nxt[ls[x]],nxt[rs[x]]);
17     }
18     inline void insert(int &x,int l,int r,int pos){
19         if(!x) x=++seg;
20         if(l==r){
21             pre[x]=nxt[x]=pos;
22             len[x]=0;
23             return;
24         }int mid=l+r>>1;
25         if(pos<=mid) insert(ls[x],l,mid,pos);
26         else insert(rs[x],mid+1,r,pos);
27         pushup(x);
28     }
29     inline void merge(int &x,int y,int l,int r){
30         if(!x||!y) {x=x+y;return;}
31         if(l==r){
32             if(pre[y]){
33                 pre[x]=nxt[x]=l;
34                 len[x]=0;
35             }
36             return;
37         }int mid=l+r>>1;
38         merge(ls[x],ls[y],l,mid);
39         merge(rs[x],rs[y],mid+1,r);
40         pushup(x);
41     }
42 }tr;
43 inline void dfs(int f,int x){
44     for(int i=head[x];i;i=e[i].next){
45         int y=e[i].to; if(y==f) continue;
46         dfs(x,y);
47         tr.merge(rt[x],rt[y],1,m);
48     }
49     if(!tr.pre[rt[x]]) ans[x]=-1;
50     else ans[x]=max(tr.pre[rt[x]]+m-tr.nxt[rt[x]]-1,tr.len[rt[x]]);
51 }
52 namespace WSN{
53     inline short main(){
54         scanf("%d%d%d",&n,&m,&q);
55         for(int i=1,u,v;i<n;i++){
56             scanf("%d%d",&u,&v);
57             add(u,v); add(v,u);
58         }
59         for(int i=1,u,pos;i<=q;i++){
60             scanf("%d%d",&u,&pos);
61             tr.insert(rt[u],1,m,pos);
62         }dfs(0,1);
63         for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
64         return 0;
65     }
66 }
67 signed main(){return WSN::main();}
View Code

T3 Connect

本次考試第二坑點,打了$spj$函式卻沒有呼叫。。。。失掉20分。。

兩處失誤當時只要是挽回一處都不會墊底。。。。

以後考試結束前十分鐘一定要抽出時間檢查自己提交的程式碼,不能再出失誤了。。

資料範圍提示狀態壓縮$dp$,思路比較神

$1$號點到$N$的路徑唯一相當於存在一條$1$到$N$的鏈, 並且不在鏈上的每個聯通塊最多隻和鏈上的一個點有連邊

類似這樣。那麼我們要預處理出來的值就知道了。

$sum[S]$表示狀態$S$的聯通塊中的邊權總和

$to[S][i]$表示聯通塊$S$到$i$點的連邊總和

那麼$dp_{S,i}$就表示目前的狀態為$S$,鏈的末端點為$i$的邊權最大值,最後用總邊權減去就可以得到刪去邊的最小值

看題解是完全能看明白的,粘一張圖片

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 const int NN=17;
 5 int n,m,g[NN][NN],U,dp[1<<NN][NN],sum[1<<NN],to[1<<NN][NN];
 6 inline void pre(){
 7     for(int S=1;S<=U;S++) for(int i=0;i<n;i++) for(int j=i+1;j<n;j++)
 8         if((S>>i&1)&&(S>>j&1)) sum[S]+=g[i][j];
 9     for(int S=1;S<=U;S++) for(int i=0;i<n;i++) for(int j=0;j<n;j++)
10         if((S>>j&1)&&g[i][j]) to[S][i]+=g[i][j];
11 }
12 namespace WSN{
13     inline short main(){
14         scanf("%lld%lld",&n,&m); U=(1<<n)-1;
15         for(int i=1,u,v,w;i<=m;i++){
16             scanf("%lld%lld%lld",&u,&v,&w);--u;--v;
17             g[u][v]=g[v][u]=w;
18         }
19         pre(); memset(dp,-1,sizeof(dp));
20         dp[1][0]=0;
21         for(int S=1;S<=U;S++) for(int i=0;i<n;i++){
22             if(dp[S][i]==-1)continue;
23             for(int j=0;j<n;j++) if(!(S>>j&1)&&g[i][j]) dp[S|(1<<j)][j]=max(dp[S][i]+g[i][j],dp[S|(1<<j)][j]);
24             int CS=U^S;
25             for(int j=CS;j;j=(j-1)&CS) dp[S|j][i]=max(dp[S|j][i],dp[S][i]+to[j][i]+sum[j]);
26         }printf("%lld\n",sum[U]-dp[U][n-1]);
27         return 0;
28     }
29 }
30 signed main(){return WSN::main();}
View Code

連續兩次了,這次比上一次考得還糟糕,上次明顯是T1比較傻,沒想到用優先佇列優化,這次更噁心

直接掛分掛到墊底要知道離真正的考試越來越近了,要是現在模擬的時候再不認真,最後你一定會後悔現在你的所做所為,

就像你今天改T2時候瘋狂不知道如何打出動態開點一樣傻 ,反正機會越來越少,怎麼也沒辦法逃脫進B的事實,

原來不管是真的沒有思路也好,一場因為沒有關freopen也好,還是因為馬虎錯誤掛分也好,都已經為分層的失敗作出了大貢獻,

而且還是不能改變的貢獻。消除這些負貢獻的最好方法不是考完試之後找回很快把題改完,這頂多表示你對這些題都有一定的思路,其他還有什麼呢

你有思路為什麼不能考場上A掉呢?為什麼不能用程式碼實現思路呢?還是之前語言學習時候的不走心,或是當時對OI的偏見。

不過,你現在的成績就是不理想,反映出來的就是你實力不行,就是你還無法達到標準。再怎麼解釋也沒用,

從小就比較反感那些考完試拍大腿的人,結果也快活成那樣了,要改變呀~~~。