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

 

posted @ 2020-09-22 20:35  Anonytt  阅读(865)  评论(0编辑  收藏  举报