2019icpc陕西省赛
前言:学长下了硬指标要我们把题补到金牌线,那就补吧。总的来说拿金牌可能并不难,就我目前能力所及(4个签到+1个思维+1个图论)可能除了图论题我现场调不完(事实上我调了整整一天qwq,不过没有用题解给的前缀和,用了自己擅长的Segment_Tree来写。)另外5个题我现场能写出来吧,大概就是在去年以我现在的水准solo能拿个银?(你在想peach)。这套题的质量我觉得很好,开场几个签到也很有意思。I题用了dfs序+线段树最后ac了。
E:Turn it off
其实就是很单纯的二分吧,不过我写的时候Re了,注意跳到最后如果跳出了记得break
#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; 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 */
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; } }
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 */
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; } }
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)); } }