2019icpc陝西省賽(部分題解)
前言:學長下了硬指標要我們把題補到金牌線,那就補吧。總的來說拿金牌可能並不難,就我目前能力所及(4個簽到+1個思維+1個圖論)可能除了圖論題我現場調不完(事實上我調了整整一天qwq,不過沒有用題解給的字首和,用了自己擅長的Segment_Tree來寫。)另外5個題我現場能寫出來吧,大概就是在去年以我現在的水準solo能拿個銀?(你在想peach)。這套題的質量我覺得很好,開場幾個簽到也很有意思。I題用了dfs序+線段樹最後ac了。
E:Turn it off
其實就是很單純的二分吧,不過我寫的時候Re了,注意跳到最後如果跳出了記得break
#include<bits/stdc++.h> #pragmaView CodeGCC optimize(2) #define ll long long #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,n,a) for(int i=n;i>=a;i--) #define endl '\n' #define eps 0.000000001 #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define IO ios::sync_with_stdio(false);cin.tie(0); using namespace std; const int INF=0x3f3f3f3f; const ll inf=0x3f3f3f3f3f3f3f3f; const int mod=1e9+7; const int maxn=1e5+5; string s;int n,k; bool check(int x){ int cur; for(int i=1;i<=n;i++){ if(s[i]=='1'){ cur=i;break; } } int cnt=0; while(cur<=n){ cur+=x;cnt+=1; if(cur>n) break; while(s[cur]=='0') ++cur; } if(cnt<=k) return true; return false; } int main(){ int T;scanf("%d",&T); while(T--){ scanf("%d%d",&n,&k); cin>>s;s=" "+s; int l=1,r=n/k+1; while(l<r){ int mid=(l+r)>>1; if(check(mid)) r=mid; else l=mid+1; } printf("%d\n",l); } } /* 1 12 4 000100000000 */
F:K-hour-clock
就是純思維題,想清楚兩者的關係,如果x+y==z直接ok的,否則看x+y-z與x和z的大小關係。
#include<bits/stdc++.h> #pragma GCC optimize(2) #define ll long long #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,n,a) for(int i=n;i>=a;i--) #define endl '\n' #define eps 0.000000001 #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define IO ios::sync_with_stdio(false);cin.tie(0); using namespace std; const int INF=0x3f3f3f3f; const ll inf=0x3f3f3f3f3f3f3f3f; const int mod=1e9+7; const int maxn=1e5+5; int main(){ int T;scanf("%d",&T); while(T--){ int x,y,z;scanf("%d%d%d",&x,&y,&z); ll cur=x+y-z; if(x+y==z){ cout<<max(x,z)+1<<endl;continue; } if(cur<=x||cur<=z){puts("-1");continue;} cout<<cur<<endl; } } /* 1 0 5 6 */View Code
L:Digit Product
這個也是思維規律題,可以發現連續的10個數必定為0,然後你先特判一下L,R的間距唄,如果小於10直接暴力上
#include<bits/stdc++.h> #pragma GCC optimize(2) #define ll long long #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,n,a) for(int i=n;i>=a;i--) #define endl '\n' #define eps 0.000000001 #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define IO ios::sync_with_stdio(false);cin.tie(0); using namespace std; const int INF=0x3f3f3f3f; const ll inf=0x3f3f3f3f3f3f3f3f; const int mod=1e9+7; const int maxn=1e5+5; ll f(ll x){ ll ans=1; while(x){ ans*=(x%10); x/=10; } return ans; } int main(){ int T;cin>>T; ll ans=0; while(T--){ int l,r;cin>>l>>r; if(r-l+1>=10){ cout<<"0"<<endl; continue; } ll ans=1; rep(i,l,r){ ans=(ans*f(i))%mod; } cout<<ans<<endl; } }View Code
B:Grid with Arrows
圖論歐拉回路+並查集判斷。找indeg,符合歐拉回路的情況先用dsu判斷是否都在1棵樹上,倘若不會直接No,如果是的話再看每個點的入度,只准有0個或1個點的入度為0這個時候輸出Yes,其他輸出No
#include<bits/stdc++.h> #pragma GCC optimize(2) #define ll long long #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,n,a) for(int i=n;i>=a;i--) #define endl '\n' #define eps 0.000000001 #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define IO ios::sync_with_stdio(false);cin.tie(0); using namespace std; const int INF=0x3f3f3f3f; const ll inf=0x3f3f3f3f3f3f3f3f; const int mod=1e9+7; const int maxn=1e5+5; int fa[maxn]; int find(int x){ while(x!=fa[x]){ x=fa[x]=fa[fa[x]]; } return x; } int main(){ int T;scanf("%d",&T); while(T--){ int n,m;scanf("%d%d",&n,&m); int indeg[n+5][m+5];mem(indeg,0); char a[n+5][m+5];mem(a,0); rep(i,1,n){ rep(j,1,m){ cin>>a[i][j]; fa[(i-1)*m+j]=(i-1)*m+j; } } rep(i,1,n){ rep(j,1,m){ int qwq;cin>>qwq; if(a[i][j]=='u'){ if(i-qwq>0){ indeg[i-qwq][j]+=1; int eu=find((i-1)*m+j); int ev=find((i-qwq-1)*m+j); if(eu!=ev) fa[ev]=eu; } } if(a[i][j]=='d'){ if(i+qwq<=n){ indeg[i+qwq][j]+=1; int eu=find((i-1)*m+j); int ev=find((i+qwq-1)*m+j); if(eu!=ev) fa[ev]=eu; } } if(a[i][j]=='r'){ if(j+qwq<=m){ indeg[i][j+qwq]+=1; int eu=find((i-1)*m+j); int ev=find((i-1)*m+j+qwq); if(eu!=ev) fa[ev]=eu; } } if(a[i][j]=='l'){ if(j-qwq>0){ indeg[i][j-qwq]+=1; int eu=find((i-1)*m+j); int ev=find((i-1)*m+j-qwq); if(eu!=ev) fa[ev]=eu; } } } } int cnt=0; rep(i,1,n){ rep(j,1,m){ if(indeg[i][j]==0){ ++cnt; } if(cnt==2){ break; } } } int cur=find(2),lol=1; rep(i,2,n*m){ if(find(i)!=find(i-1)){ lol=0; } } if((cnt==1||cnt==0)&&lol==1) puts("Yes"); else puts("No"); } } /* 1 2 3 rdd url 2 1 1 1 1 2 */View Code
C:0689
思維題,我隊友說這個可能只有CF1700的難度。我後來想想也是如此。做法大概就是利用字首和。如果當前是0,則找後面0的數量;如果當前是8,則找後面8的數量;如果當前是6,則找後面9的數量;如果是9,則找後面6的數量。總而言之大概意思就是0和0互換還是當前不變的,8和8不變,9和6不變,6和9不變。然後總共次數是(n+1)*n/2。然後記得這個題有個坑。必須執行一次操作,如果是66的話,其實只有3個變形,因為66是沒有執行操作的
#include<bits/stdc++.h> #pragma GCC optimize(2) #define ll long long #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,n,a) for(int i=n;i>=a;i--) #define endl '\n' #define eps 0.000000001 #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define IO ios::sync_with_stdio(false);cin.tie(0); using namespace std; const int INF=0x3f3f3f3f; const ll inf=0x3f3f3f3f3f3f3f3f; const int mod=1e9+7; const int maxn=1e6+5; int a[maxn],b[maxn],c[maxn],d[maxn]; int main(){ int T;scanf("%d",&T); while(T--){ string s;cin>>s; int len=s.length(); s=" "+s; for(int i=0;i<=len;i++){ a[i]=b[i]=c[i]=d[i]=0; } rep(i,1,len){ if(s[i]=='0') a[i]=a[i-1]+1; else a[i]=a[i-1]; if(s[i]=='6') b[i]=b[i-1]+1; else b[i]=b[i-1]; if(s[i]=='8') c[i]=c[i-1]+1; else c[i]=c[i-1]; if(s[i]=='9') d[i]=d[i-1]+1; else d[i]=d[i-1]; } ll ans=1ll*(len+1)*len/2+1; ans-=(a[len]+c[len]); rep(i,1,len){ if(s[i]=='0') ans-=a[len]-a[i]; if(s[i]=='6') ans-=d[len]-d[i]; if(s[i]=='8') ans-=c[len]-c[i]; if(s[i]=='9') ans-=b[len]-b[i]; } if(b[len]==len||d[len]==len) ans--; cout<<ans<<endl; } }View Code
I:Unrooted Trie
樹上dfs序+線段樹。
首先檢查每個節點的邊集,如果在邊集中出現aaa或aabb這樣的重複情況,必然是不行的,直接輸出0。然後搞dfs序。
然後遍歷每個節點,首先確定這個節點邊集中兩條重複的邊對應的點t1,t2。然後分類討論。
如果這個節點在DFS序裡在t1,t2的前面,則是t1,t2的根,那麼合法的根節點就是t1,t2的子樹,就確定了這個節點的合法根節點區間。
如果這個節點在DFS序裡在t1,t2的中間,則合法的根節點是t1的子樹的補集加上t2的子樹,儲存這個節點的合法根節點區間。
最後用線段樹統計點大小為0的數量即可。
注意細節吧。
#include<bits/stdc++.h> #pragma GCC optimize(2) #define ll long long #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,n,a) for(int i=n;i>=a;i--) #define endl '\n' #define eps 0.000000001 #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define IO ios::sync_with_stdio(false);cin.tie(0); using namespace std; const int INF=0x3f3f3f3f; const ll inf=0x3f3f3f3f3f3f3f3f; const int mod=1e9+7; const int maxn=1e5+5; class segment_tree{ public: struct node{ int l,r; int sum,lz; }tree[maxn<<2]; inline void build(int i,int l,int r){ tree[i].l=l;tree[i].r=r;tree[i].lz=0; if(l==r){ tree[i].sum=0; return ; } int mid=(l+r)>>1; build(i*2,l,mid); build(i*2+1,mid+1,r); tree[i].sum=tree[2*i].sum+tree[2*i+1].sum; } inline void push_down(int i){ if(tree[i].lz!=0){ tree[2*i].lz=tree[i].lz; tree[2*i+1].lz=tree[i].lz; int mid=(tree[i].l+tree[i].r)/2; tree[2*i].sum=tree[i].lz*(mid-tree[2*i].l+1); tree[2*i+1].sum=tree[i].lz*(tree[2*i+1].r-mid); tree[i].lz=0; } return ; } inline void add(int i,int l,int r,int k){ if(tree[i].r<=r&&tree[i].l>=l){ tree[i].sum=k*(tree[i].r-tree[i].l+1); tree[i].lz=k; return ; } push_down(i); if(tree[i*2].r>=l) add(i*2,l,r,k); if(tree[i*2+1].l<=r) add(i*2+1,l,r,k); tree[i].sum=tree[i*2].sum+tree[i*2+1].sum; } inline int search(int i,int l,int r){ if(tree[i].l>=l&&tree[i].r<=r) return tree[i].sum; if(tree[i].r<l||tree[i].l>r) return 0; push_down(i); int s=0; if(tree[i*2].r>=l) s+=search(i*2,l,r); if(tree[i*2+1].l<=r) s+=search(i*2+1,l,r); return s; } }st; int tot,head[maxn]; struct E{ int to,next; char w; }edge[maxn<<1]; void add(int u,int v,char w){ edge[tot].to=v; edge[tot].w=w; edge[tot].next=head[u]; head[u]=tot++; } int n,tim,dfn[maxn],siz[maxn]; void dfs1(int x,int f){ siz[x]=1; dfn[x]=++tim; for(int i=head[x];i!=-1;i=edge[i].next){ int v=edge[i].to; if(v==f) continue; dfs1(v,x); siz[x]+=siz[v]; } } int main(){ int T;scanf("%d",&T); while(T--){ scanf("%d",&n); fill(head,head+2*n+5,-1); fill(dfn,dfn+n+5,0); fill(siz,siz+n+5,0); tot=0,tim=0; for(int i=1;i<n;i++){ int u,v;char w;scanf("%d %d %c",&u,&v,&w); add(u,v,w);add(v,u,w); } int fg=0; for(int x=1;x<=n;x++){ int vn[30];mem(vn,0); for(int i=head[x];i!=-1;i=edge[i].next){ char w=edge[i].w; vn[w-'a']+=1; } int qwqwq=0; rep(i,0,25){ if(vn[i]>=2) qwqwq++; if(vn[i]>=3){ fg=1;break; } } if(fg) break; if(qwqwq>=2){ fg=1;break; } } if(fg){puts("0");continue;} dfs1(1,0); st.build(1,1,n); for(int u=1;u<=n;u++){ map<char,int> mp; for(int j=head[u];j!=-1;j=edge[j].next){ int v=edge[j].to;char w=edge[j].w; if(!mp[w]) mp[w]=v; else{ int f1=mp[w],f2=v; if(dfn[f1]>dfn[u]&&dfn[f2]>dfn[u]){ int L,R; if(dfn[f1]<dfn[f2]){L=f1,R=f2;} else{L=f2,R=f1;} st.add(1,1,dfn[L]-1,1); if(dfn[L]+siz[L]>n) goto end; st.add(1,dfn[L]+siz[L],dfn[R]-1,1); end:; if(dfn[R]+siz[R]>n) break; st.add(1,dfn[R]+siz[R],n,1); } else if(dfn[f1]>dfn[u]&&dfn[u]>dfn[f2]){ st.add(1,dfn[u],dfn[f1]-1,1); if(dfn[f1]+siz[f1]>n) break; st.add(1,dfn[f1]+siz[f1],dfn[u]+siz[u]-1,1); } else if(dfn[f2]>dfn[u]&&dfn[u]>dfn[f1]){ st.add(1,dfn[u],dfn[f2]-1,1); if(dfn[f2]+siz[f2]>n) break; st.add(1,dfn[f2]+siz[f2],dfn[u]+siz[u]-1,1); } break; } } } printf("%d\n",n-st.search(1,1,n)); } }View Code