2018ICPC徐州赛区网络预赛

今天打了这个比赛,水题挺多~(体验很好(太菜了))
传送门:https://www.jisuanke.com/contest/1557?view=challenges

~A. Hard to prepare

组合数学+递推(通过率: 76.7 %,通过人数: 507)

思路:考虑各个位置有几种选法,对于n,k来说,位置1有2^k种选法,接下来的每一个位置和前一个位置不能完全不同[$1]
,所以有2^k-1种选法,对于位置n,它既要顾及位置n-1的又要顾及位置1,所以就只有2^k-2种选法
但是如果位置n-1和位置1一样,那么位置n-1会多出来一种选法,此时位置n-1和n就是固定的了,前n-2个位置的选法个数变成一个子问题
需要注意的是如果n=1,答案就是2^k,n=2,答案就是2^k*(2^k-1)

$1:(因为完全不同的个数有1个,对于5:101b来说完全不同的只有2:010b)

// https://nanti.jisuanke.com/t/31453
#include<stdio.h>
typedef long long ll;
const int mod=1e9+7;
ll pow(ll x,ll y){
    ll ret=1;
    for(;y;y/=2,x=x*x%mod)
        if(y&1)ret=ret*x%mod;
    return ret;
}
int main(){
#ifdef LOCAL_DEBUG
    freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
    int t,n,k;scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&k);
        ll ans,_2k=pow(2,k);
        ans=_2k*(n%2?1:_2k-1)%mod;
        for(int i=4-n%2;i<=n;i+=2)
            ans+=_2k*(_2k-2)%mod*pow(_2k-1,i-2)%mod;
        printf("%lld\n",ans%mod);
    }
    return 0;
}

~B. BE, GE or NE

博弈规则+记忆化爆搜(通过率: 66.92 %,通过人数: 356)

思路:像数位dp一样dfs搜索,用博弈规则来转移

// https://nanti.jisuanke.com/t/31454
#include<stdio.h>
#include<string.h>
typedef long long ll;
#define only(i,ending) (i==ending||i==2)
#define have(i,ending) (i==ending)
const int maxn=1005,good=1,normal=0,bad=-1;
struct node{int a,b,c;
    inline node(int a=0,int b=0,int c=0):a(a),b(b),c(c){}
}arr[maxn];
int rounds,initscore,goodend,badend;
int ending[maxn][201];
int dfs(int round,int score){
    if(score>+100)score=+100;
    if(score<-100)score=-100;
    if(round>rounds)
        return (score>=goodend)-(score<=badend);
    if(ending[round][score]!=0x3f3f3f3f)
        return ending[round][score];
    int res=0,a=2,b=2,c=2;
    if(arr[round].a)
        a=dfs(round+1,score+arr[round].a);
    if(arr[round].b)
        b=dfs(round+1,score-arr[round].b);
    if(arr[round].c)
        c=dfs(round+1,score*-1);
    if(round&1==1)//want good ending
        if(have(a,good)+have(b,good)+have(c,good))
            return ending[round][score]=good;
        else if(only(a,bad)*only(b,bad)*only(c,bad))
            return ending[round][score]=bad;
        else
            return ending[round][score]=normal;
    else
        if(have(a,bad)+have(b,bad)+have(c,bad))
            return ending[round][score]=bad;
        else if(only(a,good)*only(b,good)*only(c,good))
            return ending[round][score]=good;
        else
            return ending[round][score]=normal;
}
char ans[3][7]={"Bad","Normal","Good"};
int main(){
#ifdef LOCAL_DEBUG
    freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
    while(~scanf("%d%d%d%d",&rounds,&initscore,&goodend,&badend)){
        memset(ending,0x3f,sizeof ending);
        for(int i=1;i<=rounds;i++)
            scanf("%d%d%d",&arr[i].a,&arr[i].b,&arr[i].c);
        printf("%s Ending\n",ans[dfs(1,initscore)+1]);
    }
    return 0;
}

F. Features Track

签到模拟(通过率: 88.66 %,通过人数: 1087)

思路:用滚动map维护上一帧出现的点,暴力更新答案,不过每一次用指针new一个O(1)而不是O(n)的clear(不过没什么卵用)

// https://nanti.jisuanke.com/t/31458
#include<stdio.h>
#include<map>
#define newmap m[i&1]
#define lastmap m[1-i%2]
struct Node{
    int x,y;
    Node(int xx=0,int yy=0){
        xx=x;
        yy=y;
    }
    bool operator<(const Node&other)const{
        return x==other.x?y<other.y:x<other.x;
    }
    bool operator>(const Node&other)const{
        return !(*this<other||*this==other);
    }
    bool operator==(const Node&other)const{
        return x==other.x&&y==other.y;
    }
}node;
std::map<Node,int>*m[2];
int main(){
#ifdef LOCAL_DEBUG
    freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
    int t;scanf("%d",&t);
    while(t--){
        m[1]=new std::map<Node,int>();
        int n,max=0;scanf("%d",&n);
        for(int i=0;i<n;i++){
            newmap=new std::map<Node,int>();
            int k;scanf("%d",&k);
            while(k--){
                scanf("%d%d",&node.x,&node.y);
                newmap->operator[](node)=1;
            }
            auto it=newmap->begin(),jt=lastmap->begin();
            while(it!=newmap->end()&&jt!=lastmap->end()){
                if(jt->first<it->first)
                    jt++;
                else if(jt->first>it->first)
                    it++;
                else{
                    it->second+=jt->second;
                    if(it->second>max)
                        max=it->second;
                    it++,jt++;
                }
            }
        }
        if(max==1)
            puts("0");
        else
            printf("%d\n",max);
    }
    return 0;
}

G. Trace

逆向输入+线段树(通过率: 72.86 %,通过人数: 663)

思路:反向加每一个矩形(避免后效性)
用一横一竖两颗线段树维护区间最大值
每次查询的答案就是是x[i]+y[i]-h.query(xp)-v.query(yp)
h=horizontal 水平的,v=vertical 垂直的

// https://nanti.jisuanke.com/t/31459
#include<stdio.h>
#include<string.h>
#include<algorithm>
const int maxn=50005;
typedef int Array[(1<<17)+2];
int max(int x,int y){return x>y?x:y;}
#define upd(pos,lazy) arr[pos]=max(lazy,arr[pos]),lz[pos]=max(lazy,lz[pos])
struct segtree{
    Array arr,lz;
    int M,ss[30],top,ans,L,R;
    void init(int n){
        memset(arr,0,sizeof arr);
        memset(lz,0,sizeof lz);
        M=1;while(M-2<n)M*=2;
    }
    bool lzdown(int u){
        if(u>M)u/=2;
        for(top=0;u;u/=2)ss[top++]=u;
        while(top--)
            if(lz[u=ss[top]])
                upd(u*2,lz[u]),upd(u*2+1,lz[u]),lz[u]=0;
        return true;
    }
    void update(int l,int r,int val){
        for(L=R=0,l+=M-1,r+=M+1;l^r^1;l/=2,r/=2){
            if(~l&1&&(L||lzdown(L=l^1)))upd(l^1,val);
            if( r&1&&(R||lzdown(R=r^1)))upd(r^1,val);
        }
        for(L/=2;L;L/=2)arr[L]=max(arr[L*2],arr[L*2+1]);
        for(R/=2;R;R/=2)arr[R]=max(arr[R*2],arr[R*2+1]);
    }
    int query(int x){
        lzdown(x+=M);
        return arr[x];
    }
}v,h;
typedef int array[maxn];
array x,sortedx,y,sortedy;
int main(){
#ifdef LOCAL_DEBUG
    freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
    for(int n;~scanf("%d",&n);){
        for(int i=0;i<n;i++)
            scanf("%d%d",x+i,y+i);
        memcpy(sortedx,x,n*4);
        memcpy(sortedy,y,n*4);
        std::sort(sortedx,sortedx+n);
        std::sort(sortedy,sortedy+n);
        long long ans=0;
        v.init(n+1);h.init(n+1);
        for(int i=n-1;~i;i--){
            int xp=std::lower_bound(sortedx,sortedx+n,x[i])-sortedx+1;
            int yp=std::lower_bound(sortedy,sortedy+n,y[i])-sortedy+1;
            ans+=x[i]+y[i]-h.query(xp)-v.query(yp);
            h.update(1,xp,y[i]);
            v.update(1,yp,x[i]);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

H. Ryuji doesn’t want to study

简单线段树(通过率: 75.87 %,通过人数: 1025)

思路:两颗线段树,一棵维护(n+1-i)*a[i],另一颗维护a[i]的区间和,单点更新区间求和
注:下面的代码是zkw线段树的

// https://nanti.jisuanke.com/t/31460
#include<stdio.h>
#include<string.h>
typedef long long ll;
const int maxn=100005;
ll arr[(1<<18)+2],iarr[(1<<18)+2],M;
void update(ll*a,int x,ll val){
    for(a[x+=M]=val,x/=2;x;x/=2)
        a[x]=a[2*x]+a[2*x+1];
}
ll query(ll*a,int l,int r){
    ll ans=0;
    for(l+=M-1,r+=M+1;l^r^1;l/=2,r/=2){
        if(~l&1)ans+=a[l^1];
        if( r&1)ans+=a[r^1];
    }
    return ans;
}
int main(){
#ifdef LOCAL_DEBUG
    freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
    for(int n,q;~scanf("%d%d",&n,&q);){
        M=1;while(M-2<n)M*=2;
        for(int i=M+1;i<=M+n;i++)
            scanf("%lld",arr+i);
        for(int i=M+1;i<=M+n;i++)
            iarr[i]=arr[i]*(M+n+1-i);
        for(int i=M;i;i--)
            arr[i]=arr[i*2]+arr[i*2+1],
            iarr[i]=iarr[i*2]+iarr[i*2+1];
        for(int op,l;q--;){
            ll r;
            scanf("%d%d%lld",&op,&l,&r);
            if(op==1){
                ll ret1=query(arr,l,r);
                ll ret2=query(iarr,l,r);
                printf("%lld\n",ret2-ret1*(n-r));
            }else{
                update(arr,l,r);
                update(iarr,l,(n+1-l)*r);
            }
        }
    }
    return 0;
}

I. Characters with Hash

签到模拟(通过率: 92.93 %,通过人数: 1485)

思路:就按照题目说的做:把所有字母变成两位的数字,然后去掉前导零,最后输出这个数字串长度
注意1 a a的情况,答案是1

// https://nanti.jisuanke.com/t/31461
#include<stdio.h>
char s[1000005];
int abs(int x){return x<0?-x:x;}
int main(){
#ifdef LOCAL_DEBUG
    freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
    int t;scanf("%d",&t);
    while(t--){
        int n;char c,*p;
        scanf("%d %c%*c",&n,&c);
        gets(s);
        int ans=0;
        for(p=s;*p;p++){
            if(*p!=c){
                ans+=1+(abs(*p++-c)>=10);
                break;
            }
        }
        ans+=2*(s-p+n);
        if(ans==0&&n)
            ans++;
        printf("%d\n",ans);
    }
    return 0;
}

~J. Maze Designer

最小生成树+LCA+倍增(通过率: 78.55 %,通过人数: 227)

思路:在给定的图中找到最大生成树(和最小生成树同理),然后在这棵树上对于每一个询问输出一个树上距离,可以用LCA+倍增在线回答

// https://nanti.jisuanke.com/t/31462
#include<stdio.h>
#include<string.h>
#include<algorithm>
const int maxn=250005;
#define nowcoord i*n+j+1
#define rightcoord i*n+j+2
#define downcoord i*n+j+n+1
int prev[maxn];
int n,m,q,w;char op[2];
void init(){for(int i=0;i<=n*m;i++)prev[i]=i;}
int find(int x){return x==prev[x]?x:prev[x]=find(prev[x]);}
void join(int x,int y){prev[find(x)]=prev[find(y)];}
bool same(int x,int y){return find(x)==find(y);}
struct setedge{
    int u,v,w;
}e[maxn*2];
struct edge{
    int dest,dist;
    struct edge*next;
}ee[maxn*2],*head[maxn];
int cnt,knt;
void addsetedge(int u,int v,int w){
    e[cnt].u=u;e[cnt].v=v;e[cnt++].w=w;
}
void addedge(setedge&x){
    ee[knt].dest=x.v;
    ee[knt].dist=x.w;
    ee[knt].next=head[x.u];
    head[x.u]=ee+knt++;
    ee[knt].dest=x.u;
    ee[knt].dist=x.w;
    ee[knt].next=head[x.v];
    head[x.v]=ee+knt++;
}
int pre[maxn][20],deep[maxn],dist[maxn];
void dfs(int u,int f,int w){
    pre[u][0]=f;
    deep[u]=deep[f]+1;
    dist[u]=dist[f]+w;
    for(int i=0;pre[u][i];i++)
        pre[u][i+1]=pre[pre[u][i]][i];
    for(edge*i=head[u];i;i=i->next)
        if(i->dest!=f)
            dfs(i->dest,u,1);
}
int lca(int u,int v){
    if(deep[u]<deep[v])u^=v^=u^=v;
    int delta=deep[u]-deep[v];
    for(int i=0;delta;i++,delta/=2)
        if(delta&1)
            u=pre[u][i];
    if(u==v)
        return u;
    for(int i=19;~i;i--)
        if(pre[u][i]^pre[v][i])
            u=pre[u][i],v=pre[v][i];
    return pre[u][0];
}
int main(){
#ifdef LOCAL_DEBUG
    freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
    while(~scanf("%d%d",&n,&m)){
        memset(head,knt=cnt=0,sizeof head);
        init();
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                scanf("%s%d",op,&w);
                if(op[0]!='X')
                    addsetedge(nowcoord,downcoord,w);
                scanf("%s%d",op,&w);
                if(op[0]!='X')
                    addsetedge(nowcoord,rightcoord,w);
            }
        }
        std::sort(e,e+cnt,[](const setedge&a,const setedge&b)->bool{
            return a.w>b.w;
        });
        int c=n*m-1;
        for(int i=0;i<cnt&&c;i++)
            if(!same(e[i].u,e[i].v)){
                addedge(e[i]);
                join(e[i].u,e[i].v);
                c--;
            }
        dfs(1,0,0);
        scanf("%d",&q);
        while(q--){
            int a,b,c,d;
            scanf("%d%d%d%d",&a,&b,&c,&d);
            a=a*n+b-n;
            c=c*n+d-n;
            printf("%d\n",dist[a]+dist[c]-2*dist[lca(a,c)]);
        }
    }
    return 0;
}

打~的题是补的题,嘿嘿嘿

猜你喜欢

转载自blog.csdn.net/qq_30396205/article/details/82563576
今日推荐