时间紧,就只写最关键的高维前缀和部分
其实我一开始也不知道这样一个东西,但我也做出来了,自己yy
把他想成一个dp,毕竟前缀和本身就是最短的dp.
dp有一个思想就是我们一定要充分的假设dp[i][j]是未知的,但推出这个状态的式子是已知的,尽管你觉得这样一个推出这个状态的式子本身不可求。
很简单的,就是要求 dp[(1010...)2] d p [ ( 1010... ) 2 ] 这样一个式子的值,意思就是括号内二进制数的出现次数与改二进制数上任意1个或多个位置的0变成1的新二进制数出现的次数的和。(有点拗口)。假设该二进制数为 (1010)2 ( 1010 ) 2 如果限定所有二进制数的最高位为第4位,那么现在这个式子就不用求了,如果再增加一位至第五位,那么他表示的其实是 dp[(01010)2] d p [ ( 01010 ) 2 ] 的状态,还差一个 dp[(11010)2] d p [ ( 11010 ) 2 ] 的值,加上去就好了。
这个东西也出现在或的贪心里。复杂度O(nlogn);
一大早过来补题面。意思就是求有多少条树上路径包含所有颜色的树上路径。每个点都有颜色.
点分治不用想了。这道题唯一的难点上面已经讲了,唯一的细节就是权在点上,仔细想想加点权的顺序。具体操作看代码。
#include
#define LL long long
using namespace std;
const int _ =5e4+4,INF = 2e9;
struct edge{
int to,nt;
}e[_<<1];
int head[_],size[_],root;
bool vis[_];
int n,k,cnt,all,MX,K,col[_];
LL ans,tong1[1025],tong2[1025];
inline void add(register int a,register int b){
e[++cnt].to=a,e[cnt].nt=head[b],head[b]=cnt;
}
void getroot(register int now,register int fa){
int mx=0;size[now]=1;
for(register int i=head[now];i;i=e[i].nt){
if(vis[e[i].to]||e[i].to==fa)continue;
getroot(e[i].to,now);
size[now]+=size[e[i].to];
if(size[e[i].to]>mx)mx=size[e[i].to];
}
mx=max(mx,all-size[now]);
if(MX>mx)root=now,MX=mx;
return;
}
void dfs(register int now,register int fa,register int len){
for(register int i=head[now];i;i=e[i].nt){
if(e[i].to==fa)continue;
if(vis[e[i].to])continue;
tong1[len|(1< 1< 1< inline LL getdis(register int now,register int len){
tong1[(1< 1< 0,(1< //cout<
/*for(register int i=0;i<=K;++i){
cout<
for(register int i=0;ifor (register int j=K;j>=0;--j){
if(!((1<1<0;
for(register int i=0;i<=K;++i)ret+=tong1[i]*(tong2[(i^K)]);
//ret+=tong1[k]*(tong2[0]-1);
for(register int i=0;i<=K;++i)tong1[i]=tong2[i]=0;
//cout<
return ret;
}
void divide(register int now){
vis[now]=1;
ans+=getdis(now,0);
for(register int i=head[now];i;i=e[i].nt){
if(vis[e[i].to])continue;
ans-=getdis(e[i].to,(1< int main(){
//freopen("data.in","r",stdin);
while(~scanf("%d%d",&n,&k)){
memset(head,0,sizeof(head));
K=(1<1;
memset(vis,0,sizeof(vis));cnt=0;ans=0;
for(register int i=1;i<=n;++i)scanf("%d",&col[i]),col[i]--;
for(register int i=1;iregister int a,b;
scanf("%d%d",&a,&b);
add(a,b);add(b,a);
}
all=n;MX=INF;
getroot(1,0);
divide(root);
printf("%lld\n",ans);
}
return 0;
}
感谢YCB推荐这道稍微没有那么板子的点分治,刚刚适合我这种蒟蒻。。