T1+T2 200 T3惨遭爆零
所有回文串都是中心对称的,所以只要不存在长度为2的和长度为3的即可
排列组合可知
ans=(m)*(m-1)*(m-2)^(n-2)
码:
#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
#define P 1000000007
ll T,n,m;
ll ksm(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b%2)ans=(ans*a)%P;
b/=2;
a=(a*a)%P;
}
return ans;
}
int main()
{
freopen("anti.in","r",stdin);
freopen("anti.out","w",stdout);
scanf("%lld",&T);
while(T--)
{
scanf("%lld%lld",&n,&m);
if(n==1)
{printf("%lld\n",m%P);
continue;
}
if(n==2)
{printf("%lld\n",(m%P)*((m-1)%P)%P);
continue;
}
printf("%lld\n",(m%P)*((m-1)%P)%P*ksm((m-2)%P,n-2 )%P);
}
}
如果对一个节点求,就是裸的树形dp,,
通过前一次的答案对后一次答案的重复部分,可以化简下一个节点的答案
所以相邻节点间的转移是O(1)的
码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define eps 0.000000005
using namespace std;
double f[1000005],ans=10000000000000009;
int from,i,n,m,a,b,ru[1000005],v[1000005],fu[1000005],tot,xia[1000005],hou[2000005],zhong[2000005];
void jian(int a,int b)
{
++tot;hou[tot]=xia[a],xia[a]=tot,zhong[tot]=b;
}
void jia(int a,int b)
{
jian(a,b);
jian(b,a);
}
void dfs(int o,int fa)
{
int i;
fu[o]=fa;
f[o]=v[o];
for(i=xia[o];i!=-1;i=hou[i])
{
int nd=zhong[i];
if(nd==fa)continue;
dfs(nd,o);
if(o==1)
{
f[o]+=f[nd]*(1.0/ru[o]);
}else
{
f[o]+=f[nd]*(1.0/(ru[o]-1));
}
}
}
void dfs2(int o)//统计贡献
{
if(o==1)
{
ans=f[o];
from=o;
}else
{
double qita=f[fu[o]]-f[o]*1/ru[fu[o]];//从上面的点下来的子树去掉
if((ru[fu[o]]-1)==0) f[o]=1.0*v[o] + 1.0*(f[o]-v[o])*(ru[o]-1)/ru[o] + 1.0*v[fu[o]]*1/ru[o];
else
f[o]=1.0*v[o] + 1.0*(f[o]-v[o])*(ru[o]-1)/ru[o] + 1.0*(v[fu[o]] + (qita-v[fu[o]])*ru[fu[o]]/(ru[fu[o]]-1))*1/ru[o];
if(ans+eps>=f[o]&&ans-eps<=f[o])
{
from=min(from,o);
}
if(ans-eps>f[o])
{
ans=f[o];
from=o;
}
}
int i;
for(i=xia[o];i!=-1;i=hou[i])
{
int nd=zhong[i];
if(nd==fu[o])continue;
dfs2(nd);
}
}
int main()
{
freopen("walking.in","r",stdin);
freopen("walking.out","w",stdout);
memset(xia,-1,sizeof(xia));
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&v[i]);
}
for(i=1;i<n;i++)
{
scanf("%d%d",&a,&b);
jia(a,b);
ru[a]++;
ru[b]++;
}
dfs(1,0);
dfs2(1);
printf("%d",from);
}
。。第三题 第一位没特判 + 加数的时候直接在splay最后加。。所以链非常长,就爆栈了
可以写splay+并查集 暴力堆叠,,但常数爆炸,而这个题卡你常数,,所以需要优化(指针据说可以过)
码(卡常80):
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define N 1000006
int ch[N][2],fu[N];
int v[N],maz[N],siz[N],may[N],ma[N],fa[N],fg[N],sz[N],fz[N],rt,i,l,r,hou[N],lin,n,m,jilu[N],cnt,nn[N];
bool rev[N],cx[N];
char str[N];
long long k;
int find(int o)
{
if(o!=fa[o])fa[o]=find(fa[o]);
return fa[o];
}
void up(int o)
{
int l=ch[o][0];
int r=ch[o][1];
sz[o]=sz[l]+sz[r]+1;
}
void down(int o)
{
int l=ch[o][0];
int r=ch[o][1];
if(rev[o])
{
rev[o]^=1;rev[l]^=1;rev[r]^=1;
swap(maz[l],may[l]);swap(maz[r],may[r]);
swap(ch[l][0],ch[l][1]);swap(ch[r][0],ch[r][1]);
}
}
int getwh(int o)
{
return ch[fu[o]][0]==o?0:1;
}
void set(int o,int wh,int child)
{
ch[o][wh]=child;
if(child!=0)fu[child]=o;
up(o);
}
void rotate(int o)
{
//cout<<o<<endl;
down(o);
int fa=fu[o];
int ye=fu[fu[o]];
int wh=getwh(o);
set(fa,wh,ch[o][wh^1]);
set(o,wh^1,fa);
fu[o]=ye;
if(ye!=0)ch[ye][ch[ye][0]==fa?0:1]=o;
}
void splay(int o,int tar)
{
for(;fu[o]!=tar;rotate(o))
if(fu[fu[o]]!=tar)
getwh(o)==getwh(fu[o])?rotate(fu[o]):rotate(o);
if(tar==0)rt=o;
}
int find(int o,int wz)
{ //cout<<sz[o]<<" "<<wz<<endl;
down(o);
int l=ch[o][0],r=ch[o][1];
if(sz[l]+1==wz)return o;
if(sz[l]>=wz)return find(l,wz);
return find(r,wz-sz[l]-1);
}
int xz(int x,int y)
{
int l=find(rt,x),r=find(rt,x+y+1);
splay(l,0);splay(r,rt);
return ch[r][0];
}
void faz(int l,int r)
{ //cout<<l<<" "<<r<<endl;
int o=xz(l,r),fa=fu[o];
if(!fg[o])
{
rev[o]^=1;
swap(ch[o][0],ch[o][1]);
swap(may[o],maz[o]);
up(fa);up(fu[fa]);
}
}
void ins(int l,int r)
{
int mid=(l+r)>>1;
sz[mid]=1;
if((mid-1-l)>=0)
{
ins(l,mid-1);
ch[mid][0]=(l+mid-1)>>1;
fu[(l+mid-1)>>1]=mid;
}
if((r-mid-1)>=0)
{
ins(mid+1,r);
ch[mid][1]=(r+mid+1)>>1;
fu[(r+mid+1)>>1]=mid;
}
up(mid);
}
void dfs(int o)
{
down(o);
if(ch[o][0])
{
dfs(ch[o][0]);
}
if(o!=1&&o!=n+2)hou[++lin]=o;
if(ch[o][1])
{
dfs(ch[o][1]);
}
}
int main()
{
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
lin=1;
scanf("%d%d%lld",&n,&m,&k);
//cout<<n;
scanf("%s",str+2);//从2开始
rt=(1+n+2)>>1;
ins(1,n+2);//偏移+1
for(i=1;i<=m;i++)
{
scanf("%d%d",&l,&r);
faz(l,r-l+1);
//if(i==m/2)cout<<"p";
}//cout<<"pp";
dfs(rt);
for(i=1;i<=n+1;i++)
fa[i]=i,sz[i]=1;
for(i=2;i<=n+1;i++)
{//cout<<hou[i]<<" ";
if(str[i]=='?'&&str[hou[i]]!='?')
{
str[find(i)]=str[hou[i]];
}
if(str[i]!='?'&&str[hou[i]]=='?')
{
str[find(hou[i])]=str[i];
}
if(str[i]=='?'&&str[hou[i]]=='?')
{
int ffa=find(i);
int ffb=find(hou[i]);
if(ffa==ffb)continue;
if(siz[ffa]<siz[ffb])swap(ffa,ffb);
fa[ffa]=ffb;
if(str[ffa]!='?')
{
str[ffb]=str[ffa];
}
siz[ffb]+=siz[ffa];
}
}
for(i=2;i<=n+1;i++)
{
if(str[find(i)]=='?'&&cx[find(i)]==0)
{
cx[fa[i]]=1;
jilu[++cnt]=fa[i];
}
}
// cout<<cnt<<endl;
int now=26;
for(i=1;i<=cnt;i++)
str[jilu[i]]='a';
lin=0;
while(k)
{
nn[++lin]=k%now;
if(lin!=1)nn[lin]++;
k/=26;
}
for(i=1;i<=lin;i++)
{
{
str[jilu[cnt-i+1]]='a'+nn[i]-1;
//cout<<'a'<<" "<<nn[i]-1<<endl;
}
}
for(i=2;i<=n+1;i++)
printf("%c",str[find(i)]);
}