2017.10.2 loli测试

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)]);
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值