愈發垃圾。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 }
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 }
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 }