1. 程式人生 > 實用技巧 >2019icpc陝西省賽(部分題解)

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 */
View Code

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