[考試反思]1024csp-s模擬測試85:覺得

愈發垃圾。ios

T1基本全場切(除了RP<-inf的zkt和把人擦)c++

而後T2想了半天逐漸趨近於正解,可是由於數據有問題鍋了25分,沒什麼好說的。
T3連題意轉化都沒有完成。括號匹配轉爲+1/-1作法都看過多少次了,還不會。。。git

必定要吸收以往的經驗,不要讓時間空過數組

還有今天下午改題速度也很是慢。主要是T3。ide

掛了一個微小的不容易(但不是不會)出鍋的細節,調了兩個多小時。spa

我覺得那麼打沒有問題,可是其實考慮的並不周密。code

不要想固然,打代碼要的是精密,而不是精妙。blog

在打下每個字以前,考慮好你要爲它付出的代價。string

感謝這錯誤沒有出如今考試,感謝它沒有毀掉個人CSP-S。it

最近仍是那麼菜,簡單題差很少能拿到手了,難題什麼都想不出來。

其實也是不夠認真不夠專一吧。。。

嗯,還有22天。

 

T1:表達式密碼

在符號後的兩個0之間填加號。在-xx的兩個數字之間填加號。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 using namespace std;
 5 char s[100005];int n;
 6 int main(){
 7     scanf("%s",s+1);
 8     n=strlen(s+1);
 9     for(int i=1;i<=n;++i){
10         putchar(s[i]);
11         if(isdigit(s[i])&&s[i-1]=='-'&&isdigit(s[i+1]))putchar('+'),s[i]='+';
12         if(s[i]=='0'&&!isdigit(s[i-1])&&isdigit(s[i+1]))putchar('+'),s[i]='+';
13     }puts("");
14 }
View Code

 

T2:電壓機制

奇環上的額點必選,偶環上的不能選。

老套路,圖不會作就建一個樹,考慮非樹邊。

其實dfs獲得的樹所剩下的邊必定是返祖邊,因此不用求LCA。

樹上差分,就沒了。

數據問題:不保證聯通

 1 #include<cstdio>
 2 int fir[100005],cnt=1,l[400005],to[400005],in[200005],n,m;
 3 int w[100005],x[100005],lim,al[100005],dep[100005],ans;
 4 void link(int a,int b){l[++cnt]=fir[a];fir[a]=cnt;to[cnt]=b;}
 5 void dfs(int p){//printf("%d\n",p);
 6     al[p]=1;
 7     for(int i=fir[p];i;i=l[i])if(!al[to[i]])
 8         in[i>>1]=1,dep[to[i]]=dep[p]+1,dfs(to[i]);
 9 }
10 void DFS(int p){
11     al[p]=2;
12     for(int i=fir[p];i;i=l[i])if(al[to[i]]!=2)
13         DFS(to[i]),w[p]+=w[to[i]],x[p]+=x[to[i]];
14 }
15 int main(){//freopen("voltage.in","r",stdin);
16     scanf("%d%d",&n,&m);
17     for(int i=1,a,y;i<=m;++i)scanf("%d%d",&a,&y),link(a,y),link(y,a);
18     dfs(1);
19     for(int i=1;i<=m;++i)if(!in[i]){
20         int a=to[i<<1],b=to[i<<1|1];
21         if(dep[a]+dep[b]&1)
22             if(dep[a]<dep[b])x[b]++,x[a]--;
23             else x[a]++,x[b]--;
24         if(dep[a]+dep[b]&1^1)
25             if(dep[a]<dep[b])w[a]--,w[b]++,lim++;
26             else w[a]++,w[b]--,lim++;
27     }DFS(1);
28     if(lim==1)ans++;
29     for(int i=2;i<=n;++i)if(al[i])if(x[i]==0&&w[i]==lim)ans++;
30     printf("%d\n",ans);
31 }
View Code

 

T3:括號密碼

首先,括號匹配的題轉化爲+1/-1問題,這已是經常使用套路了,左加右減。

問題變爲:使每個子區間[l,r]的前綴和值sum知足sum[r]=sum[l-1]且對於任意$i\in [l,r]$有sum[i]>=sum[l-1]

先不考慮重疊和包含,只考慮若干個區間彼此無交集。

那麼對於每個區間,若是總的「(」和「)」不同,那麼就要把外面的括號和內部的交換。

設a[i]表示第i個子區間的總值(前綴和)。若是它是奇數那麼無解,不然它就須要從外界獲得a[i]/2個右括號。

若是是負的,那麼就要換來左括號。

然而其實不值得每一個區間都付出這麼多的代價,由於A區間須要左括號而B區間須要右括號,那麼它兩個之間互換就行了。

這樣的話咱們對於須要左括號的區間付出相應的代價,而對於須要右括號的區間再也不付出代價,這樣咱們就節約了費用。

可是尚未完,若是全部子區間所索要的左括號與右括號數量不相等,那麼就要與非選中區間的地方進行交換。

若是與外界交換的是左括號,那麼沒有代價,由於上面已經支付過了。

若是是右括號的需求更多,那麼要再付出額外的代價。

要注意,若是全部選中的子區間外的括號不夠用,那麼無解。

如今咱們成功地使每一個子區間內部的和爲0了,問題在於內部的前綴和可能小於0了。

因此找到每一個子區間最小的前綴和,若是等於0那麼就沒有關係內部已經合法(固然不會大於0啊)

若是小於0的話那麼你就須要內部調整,調整的代價爲w/2,你只須要把最靠右的w/2個'('和最靠左的w/2個')'互換就能夠合法了。

這樣咱們就計算完代價了。

若是考慮區間有交集可是不包含呢?

若[l1,r1]和[l2,r2]分別合法且l1<l2,l2<=r1,r1<r2,那麼咱們能夠根據區間2合法知道交集的最小前綴和爲0,這樣的話它的總和大於等於0。

可是若是它大於0的話,[l1,l2-1]這一段就必須小於0,不可能合法,因此[l2,r1]這一段的總和爲0。

這樣的話[l1,l2-1],[r1+1,r2]這兩部分的總和/最小前綴和也爲0。

因此咱們就把這個區間拆成了[l1,l2-1][l2,r1][r1+1,r2]3部分。拆完以後區間就沒有重疊關係,就能夠按照上面的作了。

再考慮如何處理包含關係。

若是區間A包含區間B,那麼B的總和和最小前綴和就必須是0。這樣的話咱們考慮A-B區間和A區間是徹底等價的。

因此在統計A區間的a數組和w數組的時候直接跳過B區間統計過的部分,答案不變。

因此在你統計的時候把你統計到的部分打標記,之後遇到標記就直接跳過就行了。

可是當包含和重疊關係同時出現時,要先處理重疊,否則的話會致使統計錯誤。

 1 #include<cstdio>
 2 #include<algorithm>
 3 struct Q{
 4     int l,r;
 5     friend bool operator<(Q a,Q b){return a.r-a.l<b.r-b.l;}
 6 }q[6005];
 7 int n,w[6005],a[6005],ans,tot,al[2005],Lc,Rc;char s[2055];
 8 int main(){
 9     scanf("%s%d",s+1,&n);
10     for(int i=1;i<=n;++i)scanf("%d",&q[i].l),q[i].l++;
11     for(int i=1;i<=n;++i)scanf("%d",&q[i].r),q[i].r++;
12     for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)
13         if(q[i].l<q[j].l&&q[j].l<=q[i].r&&q[i].r<q[j].r)
14             q[++n].r=q[j].r,q[n].l=q[i].r+1,q[j].r=q[i].r,q[i].r=q[j].l-1;
15         else if(q[j].l<q[i].l&&q[i].l<=q[j].r&&q[j].r<q[i].r)
16             q[++n].r=q[i].r,q[n].l=q[j].r+1,q[i].r=q[j].r,q[j].r=q[i].l-1;
17     std::sort(q+1,q+1+n);
18     for(int i=1;i<=n;++i)for(int j=q[i].l;j<=q[i].r;++j)if(!al[j])
19         a[i]+=(s[j]=='('?1:-1),w[i]=a[i]<w[i]?a[i]:w[i],al[j]=1;
20     for(int i=1;s[i];++i)if(!al[i])if(s[i]=='(')Lc++;else Rc++;
21     for(int i=1;i<=n;++i)if(a[i]&1)return puts("-1"),0;else tot+=a[i]>>1;
22     for(int i=1;i<=n;++i)if(a[i]>0)ans+=a[i]>>1;else w[i]-=a[i];
23     for(int i=1;i<=n;++i)if(w[i]<0)ans-=w[i]>>1;
24     if(tot<-Lc||tot>Rc)return puts("-1"),0;
25     printf("%d\n",ans-(tot<0?tot:0));
26 }
View Code
相關文章
相關標籤/搜索