• csp-s模拟测试b组加餐antipalindome,randomwalking,string题解


    题面:https://www.cnblogs.com/Juve/articles/11599318.html

    antipalindome:

    打表找规律?

    对于一个回文串,我们只要保证3位以内不回文即可,即只要不出现三位以内回文就合法

    对于前三位:m*(m-1)*(m-2),剩下的n-3个位置用m-2来填

    所以$ans=m*(m-1)*(m-2)^(n-2)$,注意边界的判断

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define int long long
    using namespace std;
    const int mod=1e9+7;
    const int phi=1e9+6;
    int t,n,m,ans=0;
    int q_pow(int a,int b,int p){
    	a%=p;
    	(b+=(p-1))%=(p-1);
    	int res=1;
    	while(b){
    		if(b&1) res=res*a%p;
    		a=a*a%p;
    		b>>=1;
    	}
    	return res%p;
    }
    signed main(){
    	scanf("%lld",&t);
    	while(t--){
    		ans=0;
    		scanf("%lld%lld",&n,&m);
    		if(n==1){
    			printf("%lld
    ",m%mod);
    			continue;
    		}else if(m==1){
    			puts("0");
    			continue;
    		}else if(m==2&&n==2){
    			puts("2");
    			continue;
    		}else{
    			ans=q_pow(m-2,n-2,mod)%mod;
    			for(int i=m;i>=m-1;--i){
    				(ans*=(i%mod))%=mod;
    			}
    			printf("%lld
    ",ans);
    		}
    	}
    	return 0;
    }
    

    randomwalking:

    树形dp,感觉它贼麻烦,博主也是不会了

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define int long long
    using namespace std;
    const int MAXN=1e6+4;
    const double inf=110000000000000000.0;
    int n,a[MAXN],du[MAXN],ans;
    int to[MAXN<<1],nxt[MAXN<<1],pre[MAXN],cnt=0;
    void add(int u,int v){
        ++cnt,to[cnt]=v,nxt[cnt]=pre[u],pre[u]=cnt;
    }
    double f[MAXN],g[MAXN],minn=inf;
    void dfs(int x,int fa){
        f[x]=(double)a[x];
        if(du[x]==1&&fa!=0){
            return ;
        }
        for(int i=pre[x];i;i=nxt[i]){
            int y=to[i];
            if(y==fa) continue;
            dfs(y,x);
            if(fa!=0&&du[x]!=1) f[x]+=(double)f[y]/(double)((double)du[x]-1.0);
            else f[x]+=(double)f[y]/du[x];
        }
    }
    void DFS(int x,int fa){
        for(int i=pre[x];i;i=nxt[i]){
            int y=to[i];
            if(y==fa) continue;
            g[y]=(double)a[y];
            double tmp1=(double)(g[x]-(double)a[x])*(double)du[x];
            double tmp2=tmp1-f[y];
            double tmp3=(double)(f[y]-(double)a[y])*(double)(du[y]-1.0);
            if(du[x]>1) g[y]+=(double)(tmp2/(double)(du[x]-1.0)+(double)a[x]+tmp3)/(double)(du[y]);
            else g[y]+=(double)((double)a[x]+tmp3)/(double)(du[y]);
            DFS(y,x);
        }
    }
    signed main(){
        scanf("%lld",&n);
        for(int i=1;i<=n;++i){
            scanf("%lld",&a[i]);
        }
        for(int i=1,u,v;i<n;++i){
            scanf("%lld%lld",&u,&v);
            add(u,v),add(v,u);
            ++du[u],++du[v];
        }
        dfs(1,0);
        g[1]=f[1];
        DFS(1,0);
        minn=g[1],ans=1;
        for(int i=1;i<=n;++i){
            if(g[i]<minn){
                ans=i;
                minn=g[i];
            }
        }
        printf("%lld
    ",ans);
        return 0;
    }
    

    string:

    先翻转,然后用并差集维护相同颜色的位置

    然后把k化成26进制数,对于不能确定的点用k的26进制数去确定

    区间反转用平衡树

    我们给 ′ a ′ 到 ′ z ′ 编号为 [1, 26] ,再给每个 ′ ? ′ 一个大于 26 的不同的标号,输入的串变成了一个这样的数字串,计
    为 S .
    我们直接对这个数字串去做操作,得到一个新的数字串,记为 T .
    这件事就是这个经典的问题bzoj3223:Tyvj1729文艺平衡树.
    直接把 S 和 T 的每一位用并查集并起来,表示这些标号所代表的字符一定是相同的.
    如果一个联通块内包含至少一个字母,那么这个联通块的字符都确定了.
    否则有 26 种可能,扫一遍直接分配即可.

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    #include<cmath>
    #define int long long
    using namespace std;
    const int MAXN=5e5+5;
    int n,m,k,l[MAXN],r[MAXN],b[MAXN];
    char ch[MAXN];
    bool pd[MAXN];
    struct node1{
    	int val,pos;
    }a[MAXN];
    int fa[MAXN];
    int find(int x){
    	return fa[x]=(fa[x]==x?x:find(fa[x]));
    }
    void merge(int x,int y){
    	x=find(x),y=find(y);
    	fa[max(x,y)]=min(x,y);
    }
    vector<int>v[MAXN];
    int col[MAXN],tot=-1;
    struct Node{
        bool rev;
        int s,h,v;
        Node *l,*r;
    }*root=0;
    struct tbw{
        Node *l,*r;
        tbw(){}
        tbw(Node *a,Node *b){l=a,r=b;}
    };
    int gets(Node *x){return x?x->s:0;}
    void update(Node *x){x->s=gets(x->l)+1+gets(x->r);}
    void rev(Node *x){
        if(!x) return;
        x->rev ^=1;
        swap(x->l,x->r);
    }
    void down(Node *x){
        if(x->rev) rev(x->l),rev(x->r),x->rev=0;
    }
    Node *merge(Node *a,Node *b){
        if(!a) return b;
        if(!b) return a;
        if (a->h<b->h){
            down(a);
            a->r=merge(a->r,b);
            update(a);
            return a;
        }
        down(b);
        b->l=merge(a,b->l);
        update(b);
        return b;
    }
    tbw split(Node *x,int k){
        if(!x) return tbw(0,0);
        down(x);
        int tot=gets(x->l)+1;
        if(k<tot){
            tbw a=split(x->l,k);
            x->l=a.r;
            update(x);
            return tbw(a.l,x);
        }
        tbw a=split(x->r,k-tot);
        x->r=a.l;
        update(x);
        return tbw(x,a.r);
    }
    void insert(int v){
        Node *x=new Node;
        x->h=rand(),x->l=x->r=0;
        x->v=v,x->s=1;
        root=merge(root,x);
    }
    void rev(int l,int r){
        tbw a=split(root,l-1);
        tbw b=split(a.r,r-l+1);
        rev(b.l);
        root=merge(merge(a.l,b.l),b.r);
    }
    int num=0;
    void print(Node *x){
        if(!x) return;
        down(x);
        print(x->l);
    	b[++num]=x->v;
        print(x->r);
    }
    signed main(){
    	scanf("%lld%lld%lld",&n,&m,&k);
    	scanf("%s",ch+1);
    	for(int i=1;i<=n;++i){
    		fa[i]=a[i].pos=b[i]=i;
    		a[i].val=0;
    		if(ch[i]!='?'){
    			a[i].val=ch[i]-'a'+1;
    			pd[i]=1;
    		}
    		insert(i);
    	}
    	for(int i=1;i<=m;++i){
    		scanf("%lld%lld",&l[i],&r[i]);
    		rev(l[i],r[i]);
    	}
    	print(root);
    	for(int i=1;i<=n;++i){
    		merge(b[i],i);
    	}
    	for(int i=1;i<=n;++i){
    		int x=find(i);
    		v[x].push_back(i);
    		if(a[x].val!=0) col[x]=a[x].val;
    		else if(a[i].val!=0) col[x]=a[i].val;
    	}
    	for(int i=1;i<=n;++i){
    		int x=find(i);
    		if(col[x]==0) continue;
    		a[i].val=col[x];
    	}
    	for(int i=1;i<=n;++i){
    		if(col[i]==0&&v[i].size()!=0) ++tot;
    	}
    	for(int i=1;i<=n;++i){
    		int x=find(i);
    		if(a[i].val!=0) continue;
    		else if(x!=i) a[i].val=a[x].val;
    		else if(tot>13) a[i].val=1,--tot;
    		else{
    			int p=pow(26,tot--);
    			int x=k/p;
    			if(k%p) ++x;
    			a[i].val=x--;
    			k-=x*p;
    		}
    	}
    	for(int i=1;i<=n;++i){
    		putchar(a[i].val+'a'-1);
    	}
    	puts("");
    	return 0;
    }
    
  • 相关阅读:
    CodeForces 1208 A. Boys and Girls 模拟序列
    CodeForces 1209 B. Jury Size 树状数组处理区间统计问题
    Linux环境进程间通信(转IBM)
    Qt(转IBM)
    POSIX 线程详解(转IBM)
    Perl 编程系列
    Socket in Linux(转IBM)
    Return to the Basic 限定符: const和volatile.
    SQA
    (C++)从本机获取WMI数据.
  • 原文地址:https://www.cnblogs.com/Juve/p/11599329.html
Copyright © 2020-2023  润新知