6
12
2015
0

bzoj 4033: [HAOI2015]T1

这是一类非线性的树形DP问题,首先我们想到F[i][s][j]表示以i为根的子树考虑了S中的儿子有j个黑点的答案

然后我们发现DP起来很有问题因为我们要考虑每一个子树的情况

首先利用背包的性质来进行DP 这样可以少去Sz这一为状态,空间就没有问题了

然后我们发现复杂度是这么一个东西

$$  Sum_x(size[x] * Sum_{y|y是x排在前面的兄弟}size[y])  $$

然后这个东西的复杂度是 $$ O(n^2) $$ 的具体证明不会 但是感受一下二叉树,菊花树,  链什么的都没什么问题

所以就这样了

//coder : davidwang
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <ctime>
using namespace std;
#define LL long long
#define LD long double
#define X first
#define Y second
inline int read()
{
	int ret=0,f=1; char ch;
	for (ch=getchar();ch>'9' || ch<'0';ch=getchar())
		if (ch=='-') f=-f;
	for (;'0'<=ch && ch<='9';ch=getchar())
		ret=ret*10+ch-'0';
	return ret*f;
}
const int N = 2010;
int to[N<<1],next[N<<1],len[N<<1],start[N],cnt,fa[N];
int q[N],size[N],k,n;
inline void connect(int x,int y,int z){
	to[++cnt]=y; next[cnt]=start[x];
	start[x]=cnt; len[cnt]=z;
}
LL f[N][N];
inline LL calc(int x,int i,int y,int j){
	return j * (k - j) + (size[y] - j) * (n - k - (size[y] - j));
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	n=read(); k=read();
	for (int i=1;i<n;i++){
		int x=read(),y=read(),z=read();
		connect(x,y,z);
		connect(y,x,z);
	}
	int head=0,tail=1,u,v;
	q[1]=1;
	memset(fa,-1,sizeof(fa));
	fa[1]=0;
	while (head<tail){
		u=q[++head];
		for (int p=start[u];p;p=next[p]){
			v=to[p];
			if (fa[v]==-1){
				q[++tail]=v;
				fa[v]=u;
			}
		}
	}
	for (int ii=n;ii;ii--){
		int x=q[ii];
		size[x]++;
		f[x][0]=f[x][1]=0;
		for (int p=start[x];p;p=next[p]){
			if (to[p]==fa[x]) continue;
			int y=to[p];
			for (int i=min(k,size[x]);i>=0;i--)
				for (int j=min(size[y],k-i);j>=0;j--)
					f[x][i+j]=max(f[x][i+j],f[x][i]+f[y][j]+calc(x,i,y,j)*len[p]);
			size[x]+=size[y];
		}
	}
	printf("%lld\n",f[1][k]);
}
Category: 未分类 | Tags: bzoj HNOI DP
6
11
2015
0

bzoj 4128: Matrix

我还是太弱了

如何判断两个n*n的矩阵A,B的, A*B是否等于C

我们随机一个1*n的向量 x A*B=C 等价于 x*A*B=x*C,矩阵乘法满足结合律,所以这个判断就是$$ O(n^2) $$的

然后这道题目就是枚举答案然后判断就可以了复杂度 $$ O(ans * n^2) $$ 我试了以下貌似这玩意非常难卡掉,因为我去掉判断也过掉了到套题目

//coder : davidwang
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <iostream>
#include <queue>
#include <deque>
#include <algorithm>
using namespace std;
#define LL long long
#define X first
#define Y second
inline int read()
{
	int ret=0,f=1; char ch;
	for (ch=getchar();ch>'9' || ch<'0';ch=getchar())
		if (ch=='-') f=-f;
	for (;'0'<=ch && ch<='9';ch=getchar())
		ret=ret*10+ch-'0';
	return ret*f;
}
struct Matrix{
	int x[71][71];
	int h,w;
	int operator==(const Matrix &A) const{
		if (h!=A.h || w!=A.w) return 0;
		for (int i=1;i<=h;i++)
			for (int j=1;j<=w;j++)
				if (x[i][j]!=A.x[i][j]) return 0;
		return 1;
	}
}A,B,C,Tar,now;
int mod;
Matrix operator*(const Matrix &A,const Matrix &B){
	Matrix C;
	C.h=A.h; C.w=B.w;
	for (int i=1;i<=C.h;i++)
		for (int j=1;j<=C.w;j++) C.x[i][j]=0;
	for (int i=1;i<=C.h;i++)
		for (int j=1;j<=C.w;j++)
			for (int k=1;k<=A.w;k++)
				C.x[i][j]=(C.x[i][j]+A.x[i][k]*B.x[k][j])%mod;
	return C;
}
inline Matrix power(Matrix A,LL b){
	
//	printf("check %lld\n",b);	
	
	Matrix C;
	C.h=C.w=A.h;
	for (int i=1;i<=A.h;i++)
		for (int j=1;j<=A.h;j++)
			C.x[i][j]=i==j;
	while (b){
		if (b&1) C=C*A;
		A=A*A;
		b>>=1;
	}
	return C;
}
int n;
int main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	srand(2333);
	n=read(); mod=read();
	A.h=A.w=B.h=B.w=C.w=n;
	C.h=1;
	for (int i=1;i<=n;i++) C.x[1][i]=rand()%(mod-1)+1;
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
			A.x[i][j]=read();
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
			B.x[i][j]=read();
	Tar=C*B;
	now=C*A;
	int ans=1;
	while (1){
		if (Tar==now){
			printf("%d\n",ans);
			return 0;
		}
		now=now*A;
		ans++;
	}
	return 0;
}
Category: 未分类 | Tags: bzoj 矩阵乘法
6
11
2015
2

bzoj 4127: Abs

这就是线段树解决区间覆盖的一类毒瘤问题

自从xyz111在cf上出了那道线段树解决区间覆盖问题之后,这已经几乎成为了一种毒瘤算法,这道题可以说是有过之而无不及。首先我们考虑一个区间内有正有负,加完之后绝对值的和和三部分有关系1.有负数变成负数,2.由正数变成正数,3.有负数变成正数,前面两种非常好讨论,只有第三种有苦难。但是我们注意到第三种每个数字只会出现一次,所以就变成了区间覆盖的那一类问题,用区间覆盖线段树来解决,复杂度通过势能分析。

所以树链剖分之后随便搞一搞复杂度 $$ O(nlog^2n) $$

//coder : davidwang
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <iostream>
#include <queue>
#include <deque>
#include <algorithm>
using namespace std;
#define LL long long
#define X first
#define Y second
inline int read()
{
	int ret=0,f=1; char ch;
	for (ch=getchar();ch>'9' || ch<'0';ch=getchar())
		if (ch=='-') f=-f;
	for (;'0'<=ch && ch<='9';ch=getchar())
		ret=ret*10+ch-'0';
	return ret*f;
}
const int N = 100010;
int son[N],fa[N],d[N],p[N][20],q[N],w[N],v[N],a[N],top[N],vis[N];
int start[N],to[N<<1],next[N<<1],size[N],cnt;
inline void connect(int a,int b){
	to[++cnt]=b; next[cnt]=start[a]; start[a]=cnt;
}
int n,m;
struct node{
	int l,r;
	int vmax,num;
	LL sum,flag;
	inline int mid(){ return r+l>>1; }
	inline int len(){ return r-l+1; }
	inline void add(LL x){
		if (vmax!=0 && vmax+x>=0) printf("Wrong!!!\n");
		if (vmax!=0) vmax+=x;
		flag+=x;
		sum+=x*(len()-num-num);
	} 
}s[N<<2];
void init(){
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	n=read(); m=read();
	for (int i=1;i<=n;i++) a[i]=read();
	for (int i=1;i<n;i++){
		int x=read(),y=read();
		connect(x,y);
		connect(y,x);
	}
	int head=0,tail=1,u;
	q[1]=1; d[1]=1; fa[1]=0;
	while (head<tail){
		u=q[++head];
		for (int p=start[u];p;p=next[p]){
			int &v=to[p];
			if (d[v]) continue;
			d[v]=d[u]+1; fa[v]=u;
			q[++tail]=v;
		}
	}
	for (int i=n;i;i--){
		int x=q[i];
		size[x]++;
		size[fa[x]]+=size[x];
		if (size[son[fa[x]]]<size[x]) son[fa[x]]=x;
	}
	int now=0;			
	for (int i=1;i<=n;i++){
		int x=q[i];
		if (vis[x]) continue;
		for (int j=x;j;j=son[j]){
			top[j]=x;
			w[j]=++now;
			vis[j]=1;
			v[now]=a[j];
		}
	}
	for (int i=1;i<=n;i++) p[i][0]=fa[i];
	for (int j=1;j<20;j++)
		for (int i=1;i<=n;i++)
			p[i][j]=p[p[i][j-1]][j-1];
}
inline int lca(int x,int y){
	if (d[x]<d[y]) swap(x,y);
	int j;
	while (d[x]>d[y]){
		for (j=1;d[p[x][j]]>=d[y];j++);
		x=p[x][j-1];
	}
	while (x!=y){
		for (j=1;p[x][j]!=p[y][j];j++);
		x=p[x][j-1],y=p[y][j-1];
	}
	return x;	
}
inline void push_down(int x){
	if (s[x].r>s[x].l && s[x].flag){
		s[x<<1].add(s[x].flag);
		s[x<<1|1].add(s[x].flag);
		s[x].flag=0;
	}
}
inline int gvmax(int x,int y){
	if (x>=0) return y;
	if (y>=0) return x;
	return x>y?x:y;
}
inline void push_up(int x){
	s[x].sum=s[x<<1].sum+s[x<<1|1].sum;
	s[x].num=s[x<<1].num+s[x<<1|1].num;
	s[x].vmax=gvmax(s[x<<1].vmax,s[x<<1|1].vmax);
}
inline void build(int i,int l,int r){
	s[i].l=l; s[i].r=r;
	s[i].flag=0;
	if (l==r){
		s[i].num=v[l]<0?1:0;
		s[i].vmax=min(0,v[l]);
		s[i].sum=abs(v[l]);
		return;
	}
	int m=l+r>>1;
	build(i<<1,l,m); build(i<<1|1,m+1,r);
	push_up(i);
}
inline LL query(int i,int l,int r){
	if (s[i].l==l && s[i].r==r){
		return s[i].sum;
	}
	push_down(i);
	int m=s[i].mid();
	LL ret;
	if (r<=m) ret=query(i<<1,l,r);
	else if (l>m) ret=query(i<<1|1,l,r);
	else ret=query(i<<1,l,m)+query(i<<1|1,m+1,r);
	push_up(i);
	return ret;
}
inline void dfs(int i,int d){
	if (s[i].vmax==0 || s[i].vmax+d<0){
		s[i].add(d);
		return;
	}
	if (s[i].l==s[i].r){
		s[i].sum=s[i].vmax+d;
		s[i].vmax=0;
		s[i].num=0;
		return;
	}
	push_down(i);
	dfs(i<<1,d); 
	dfs(i<<1|1,d);
	push_up(i);
}
inline void modify(int i,int l,int r,int d){
	if (s[i].l==l && s[i].r==r){
		dfs(i,d);
		return;
	}
	push_down(i);
	int m=s[i].mid();
	if (r<=m) modify(i<<1,l,r,d);
	else if (l>m) modify(i<<1|1,l,r,d);
	else modify(i<<1,l,m,d),modify(i<<1|1,m+1,r,d);
	push_up(i);
}
inline LL Query(int x,int y){
	LL ans=0;
	int u=lca(x,y);
	while (d[x]>d[u]){
		if (d[top[x]]>d[u]){
			ans+=query(1,w[top[x]],w[x]);
			x=fa[top[x]];
		}else{
			ans+=query(1,w[son[u]],w[x]);
			x=u;
		}
	}
	swap(x,y);
	while (d[x]>d[u]){
		if (d[top[x]]>d[u]){
			ans+=query(1,w[top[x]],w[x]);
			x=fa[top[x]];
		}else{
			ans+=query(1,w[son[u]],w[x]);
			x=u;
		}
	}
	ans+=query(1,w[u],w[u]);
	return ans;
}
inline void Modify(int x,int y,int D){
	int u=lca(x,y);
	while (d[x]>d[u]){
		if (d[top[x]]>d[u]){
			modify(1,w[top[x]],w[x],D);
			x=fa[top[x]];
		}else{
			modify(1,w[son[u]],w[x],D);
			x=u;
		}
	}
	swap(x,y);
	while (d[x]>d[u]){
		if (d[top[x]]>d[u]){
			modify(1,w[top[x]],w[x],D);
			x=fa[top[x]];
		}else{
			modify(1,w[son[u]],w[x],D);
			x=u;
		}
	}
	modify(1,w[u],w[u],D);
	return;
}
void work()
{
	build(1,1,n);
	for (int i=1;i<=m;i++){
		int op=read(),x=read(),y=read();
		if (op==2){
			printf("%lld\n",Query(x,y));
		}else{
			int d=read();
			Modify(x,y,d);
		}
	}
}
int main()
{
	init();
	work();
	return 0;
}

 

 

Category: 未分类 | Tags: bzoj 线段树 区间覆盖
6
4
2015
0

Thusc T3: bzoj 4104[Thu Summer Camp 2015]解密运算

首先对于一个按行向量排序的循环矩阵,任意两列都是一一对应的关系,于是我们只需要找到每行第一列和最后一列的对应关系就行了

结论1 : 第一行就是最后一行排序的结果

结论2 :这个关系是一一对应的,而且对应后的逆结果便是原序列按照字典序第一关键字,位置第二关键字排序之后的位置

这样暴力sort可以解决,然后还可以高大上的用基数排序搞到O(n)

//coder: davidwang
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define X first
#define Y second
using namespace std;
#define LL long long
inline int read(){
	int ret=0,f=1; char ch;
	for (ch=getchar();ch<'0' || ch>'9';ch=getchar())
		if (ch=='-') f=-f;
	for (;'0'<=ch && ch<='9';ch=getchar()) ret=ret*10+ch-48;
	return ret*f;
}
const int N = 200010;
pair<int,int>a[N];
int b[N],n,m;
int main()
{
	n=read(); m=read(); n++;
	for (int i=1;i<=n;i++) b[i]=read(),a[i]=make_pair(b[i],i);
	sort(a+1,a+n+1);
	for (int now=a[a[1].Y].Y;b[now];now=a[now].Y){
		printf("%d ",b[now]);
	}
}
//coder: davidwang
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#define X first
#define Y second
using namespace std;
#define LL long long
inline int read(){
	int ret=0,f=1; char ch;
	for (ch=getchar();ch<'0' || ch>'9';ch=getchar())
		if (ch=='-') f=-f;
	for (;'0'<=ch && ch<='9';ch=getchar()) ret=ret*10+ch-48;
	return ret*f;
}
const int N = 200010;
int n,m,a[N],cnt[N],next[N],now;
int main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	n=read();
	m=read();
	for (int i=1;i<=n+1;i++){
		a[i]=read(); cnt[a[i]]++;
		if (a[i]==0) now=i;
	}
	for (int i=1;i<=m;i++) cnt[i]+=cnt[i-1];
	for (int i=m;i;i--) cnt[i]=cnt[i-1]; cnt[0]=0;
	for (int i=1;i<=n+1;i++) next[++cnt[a[i]]]=i;
	int i=1;
	for (now=next[now],i=1;i<=n;i++,now=next[now])
		printf("%d ",a[now]);
	puts("");
	return 0;
}

 

发现刚才头文件比代码要长好多不科学,然后就缩减了一下……当时这么简单的题目都没能做出来.......

Category: 未分类 | Tags: bzoj THOI
6
4
2015
0

bzoj 2425: [HAOI2010]计数

题意: 给你一个数n(n<10^51),让你把他的各位数字重拍列以下,然后比他小,求方案数

非常简单的数位DP 主要是看一下代码高亮的情况

//coder : davidwang
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <vector>
#include <deque>
#include <queue>
using namespace std;
#define LL long long 
#define X first
#define Y second
inline int read()
{
	int ret=0,f=1; char ch;
	for (ch=getchar();ch<'0' || ch>'9';ch=getchar())
		if (ch=='-') f=-f;
	for (;'0'<=ch && ch<='9';ch=getchar())
		ret=ret*10+ch-'0';
	return ret*f;
}
const int N = 60;
LL ans,c[N][N],num[N];
char s[N];
inline LL calc(int x){
	LL ret=1;
	for (int i=0;i<=9;i++)
		ret*=c[x][num[i]],x-=num[i];
	return ret;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	scanf("%s",s+1);
	int n=strlen(s+1);
	for (int i=1;i<=n;i++) num[s[i]-'0']++;
	c[0][0]=1;
	for (int i=1;i<=n;i++){
		c[i][0]=1;
		for (int j=1;j<=i;j++) c[i][j]=c[i-1][j]+c[i-1][j-1];
	}
	for (int i=1;i<=n;i++){
		for (int j=0;j<s[i]-'0';j++){
			if (!num[j]) continue;
			num[j]--;
			ans+=calc(n-i);
			num[j]++;
		}
		num[s[i]-'0']--;
	}
	printf("%lld\n",ans);
	return 0;
}		
Category: 未分类 | Tags: bzoj 题解 水题集合

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com