题面: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; }