6
23
2015
0

bzoj 4155: [Ipsc2015]Humble Captains

第一问: 网络流,这并没有什么问题

第二问: 阿丽和桃子的游戏,这并没有什么问题

总之是傻逼了

//coder : davidwang
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <algorithm>
#include <vector>
#include <bitset>
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 = 210;
struct edge{
	int to,flow;
	edge(int to=0,int flow=0): to(to),flow(flow){}
}e[N*N*2];
int d[N],f[N*N*2],x[N],n,m,cnt,q[N];
vector<int>g[N];
bitset<N*N>A;
inline void connect(int a,int b,int f){
	e[cnt]=edge(b,f);
	g[a].push_back(cnt++);
	x[a]++;
	e[cnt]=edge(a,f);
	g[b].push_back(cnt++);
	x[b]++;
}
int s=1,t=2;
inline int bfs()
{
	int head=0,tail=1,u,v;
	for (int i=1;i<=n;i++) d[i]=0;
	d[s]=1; q[1]=s;
	while (head<tail){
		u=q[++head];
		for (vector<int>::iterator it=g[u].begin();it!=g[u].end();it++){
			if (e[*it].flow && !d[e[*it].to]){
				q[++tail]=e[*it].to;
				d[e[*it].to]=d[u]+1;
			}
		}
	}
	return d[t];
}
inline int dfs(int x,int flow){
	if (x==t || flow==0) return flow;
	int totflow=0,f;
	for (vector<int>::iterator it=g[x].begin();it!=g[x].end();it++){
		if (e[*it].flow && d[e[*it].to]==d[x]+1){
			f=dfs(e[*it].to,min(flow,e[*it].flow));
			flow-=f; totflow+=f;
			e[*it].flow-=f; e[(*it)^1].flow+=f;
			if (flow==0) return totflow;
		}
	}
	if (flow) d[x]=-1;
	return totflow;
}
inline void work()
{
	int ans1=0,ans2=0;
	n=read(); m=read();
	cnt=0;
	for (int i=1;i<=n;i++){
		g[i].clear();
		x[i]=0;
	}
	int cE=m; 
	for (int i=1;i<=m;i++){
		int x=read(),y=read();
		if (x+y==3) cE--;
		else connect(x,y,1);
	}
	for (int i=0;i<=m*2;i++) A[i]=0;
	A[x[1]]=1;
	while (bfs()) ans1+=dfs(s,INT_MAX);
	printf("%d ",cE-ans1);
	for (int i=3;i<=n;i++){
		A=(A<<x[i]|A);
	}
	for (int i=0;i<=cE;i++){
		if (A[cE+i]==1 || A[cE-i]==1){
			printf("%d\n",i);
			break;
		}
	}
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	int T=read();
	while (T--) work();
	return 0;
}

 

Category: 未分类 | Tags: bzoj ipsc 网络流 贪心
6
18
2015
0

bzoj 4152: [AMPPZ2014]The Captain

首先按照x,y分别排序相邻的连边然后跑最短路,这个应该是显然的,不知道用了什么卡SPFA的方法,必须用堆+Dij

//coder : davidwang
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <bitset>
#include <deque>
using namespace std;
#define LL long long
#define X first
#define Y second
template<typename T>
inline T sqr(const T &x){ return x*x; }
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 = 200010;
const LL inf = 1LL<<60;
struct point{
	int x,y,pos;
}a[N];
int start[N],next[N<<2],to[N<<2],len[N<<2],cnt;
struct node{
	LL d;
	int id;
	int operator<(const node &x)const {
		return d>x.d;
	}
	node(int id=0,LL d=0):id(id),d(d){}
};
LL d[N];
priority_queue<node>Q;
int vis[N];
inline int cmp1(const point &a,const point &b){
	return a.x<b.x;
}
inline int cmp2(const point &a,const point &b){
	return a.y<b.y;
}
inline void connect(int x,int y,int d){
	to[++cnt]=y; next[cnt]=start[x];
	start[x]=cnt; len[cnt]=d;
}
int n;
int main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	n=read();
	for (int i=1;i<=n;i++){
		a[i].x=read();
		a[i].y=read();
		a[i].pos=i;
	}
	sort(a+1,a+n+1,cmp1);
	for (int i=1;i<n;i++){
		connect(a[i].pos,a[i+1].pos,a[i+1].x-a[i].x);
		connect(a[i+1].pos,a[i].pos,a[i+1].x-a[i].x);
	}
	sort(a+1,a+n+1,cmp2);
	for (int i=1;i<n;i++){
		connect(a[i].pos,a[i+1].pos,a[i+1].y-a[i].y);
		connect(a[i+1].pos,a[i].pos,a[i+1].y-a[i].y);
	}
	for (int i=2;i<=n;i++) d[i]=inf;
	Q.push(node(1,0));
	while (!Q.empty()){
		while (Q.size() && vis[Q.top().id]) Q.pop();
		if (Q.empty()) break;
		int x=Q.top().id; Q.pop();
		vis[x]=1;
		for (int p=start[x];p;p=next[p]){
			if (d[to[p]]>d[x]+len[p]){
				d[to[p]]=d[x]+len[p];
				Q.push(node(to[p],d[to[p]]));
			}
		}
		if (vis[n]) break;
	}
	printf("%lld\n",d[n]);
	return 0;
}

 

Category: 未分类 | Tags: bzoj 堆优化Dij
6
17
2015
0

bzoj 4144: [AMPPZ2014]Petrol

就是一结论题目

首先如果所有点都是加油站,那么把询问离线维护可达的生成森林就OK了

现在有些点不是加油站

我们预处理出每个不是加油站的点距离最近的加油站,就变成了一个蜘蛛网的结构(其实是一个树)

然后我们对于原来的每条边对应这两个加油站之间的边如果原来有一条(x,y,d)的边,记bel[x]表示距离x最近的加油站,d[x]表示距离x最近的加油站的距离,那么这样一条边对应着(bel[x],bel[y],d+d[x]+d[y])这样一个点,然后问题就解决了

证明:

我还是大体证明了以下这个结论(其实就一个拟阵)

//coder : davidwang
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <bitset>
#include <deque>
using namespace std;
#define LL long long
#define X first
#define Y second
template<typename T>
inline T sqr(const T &x){ return x*x; }
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 = 200010;
const LL inf = 1LL<<60;
struct edge{
	int x,y,l,pos;
	edge(int x=0,int y=0,int l=0,int pos=0): x(x),y(y),l(l),pos(pos){}
	int operator<(const edge &A) const{
		return l<A.l || (l==A.l && pos<A.pos);
	}
}e[N*4];
vector<pair<int,int> >g[N];
vector<pair<int,int> >::iterator it;
int q[N+2],bel[N],ans[N],in[N];
LL d[N];
inline int next(int &x){ x=(x%N+1); return x;}
struct UnionFindSet{
	int Set[N],Size[N];
	inline void init(int n){
		for (int i=1;i<=n;i++){
			Set[i]=i;
			Size[i]=1;
		}
	}
	int find(int x){
		if (Set[x]==x) return x;
		Set[x]=find(Set[x]);
		return Set[x];
	}
	inline int join(int x,int y){
		x=find(x),y=find(y);
		if (x==y) return 0;
		if (Size[x]>Size[y]) swap(x,y);
		Set[x]=y; Size[y]+=Size[x];
		return 1;
	}
}s;
int n,m,T,cnt,E;
int main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	n=read(); m=read(); E=read();
	for (int i=1;i<=n;i++) d[i]=inf;
	for (int i=1;i<=m;i++){
		int x=read();
		bel[x]=x;
		d[x]=0;
		in[x]=1;
		q[i]=x;
	}
	for (int i=1;i<=E;i++){
		int x=read(),y=read(),z=read();
		g[x].push_back(make_pair(y,z));
		g[y].push_back(make_pair(x,z));
	}
	int head=0,tail=m;
	while (head!=tail){
		int u=q[next(head)];
		for (it=g[u].begin();it!=g[u].end();it++){
			if (d[it->X]>d[u]+it->Y){
				d[it->X]=d[u]+it->Y;
				bel[it->X]=bel[u];
				if (!in[it->X]){
					q[next(tail)]=it->X;
					in[it->X]=1;
				}
			}
		}
		in[u]=0;
	}
	for (int i=1;i<=n;i++)
		for (it=g[i].begin();it!=g[i].end();it++)
			if (bel[it->X] != bel[i]){
				LL now=d[i]+d[it->X]+it->Y;
				if (now>2e9) continue;
				e[++cnt]=edge(bel[i],bel[it->X],(int)now);
			}
	T=read();
	for (int i=1;i<=T;i++){
		cnt++;
		e[cnt].x=read(); e[cnt].y=read();
		e[cnt].l=read();
		e[cnt].pos=i;
	}
	sort(e+1,e+cnt+1);
	s.init(n);
	for (int i=1;i<=cnt;i++){
		if (e[i].pos==0)
			s.join(e[i].x,e[i].y);
		else
			ans[e[i].pos]=s.find(e[i].x)==s.find(e[i].y);
	}
	for (int i=1;i<=T;i++) printf("%s\n",ans[i]?"TAK":"NIE");
	return 0;
}

 

Category: 未分类 | Tags: bzoj 并查集 拟阵
6
17
2015
0

bzoj 4080: [Wf2014]Sensor Network

死活过不去的暴力?难道这就是传说中的卡最大团的暴力数据??

上网一看全都是随机化,然后完全不明白

后来想了想什么random_shuffle之后搞一下

然后就过了

对了,次数还可以卡以下所以就把T搞到80才rank3

//coder : davidwang
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <bitset>
#include <deque>
using namespace std;
#define LL long long
#define X first
#define Y second
template<typename T>
inline T sqr(const T &x){ return x*x; }
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 = 110;
bitset<N>now,ans,cur,a[N],can;
int order[N],x[N],y[N],d,n;
int main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
//	srand(2333);
	n=read(); d=read();
	d*=d;
	for (int i=1;i<=n;i++){
		x[i]=read();
		y[i]=read();
		for (int j=1;j<i;j++){
			if (sqr(x[i]-x[j])+sqr(y[i]-y[j])<=d){
				a[i][j]=a[j][i]=1;
			}
		}
	}
	for (int i=1;i<=n;i++) order[i]=i;
	for (int T=1;T<=80;T++){
		for (int i=1;i<=n;i++) can[i]=1,now[i]=0;
		for (int i=1;i<=n;i++){
			if (can[order[i]]){
				can=can&a[order[i]];
				now[order[i]]=1;
			}
		}
		if (now.count()>ans.count()) ans=now;
		random_shuffle(order+1,order+n+1);
	}
	printf("%d\n",(int)ans.count());
	for (int i=1;i<=n;i++){
		if (ans[i]) printf("%d ",i);
	}
	puts("");
	return 0;
}
Category: 未分类 | Tags: bzoj 随机化 乱搞
6
16
2015
0

bzoj 4134: ljw和lzr的hack比赛

我才不会说是被题目吸引进来的

然后就吓傻了,我还以为是那种朴素的森林取子问题,节点sg就是字节点抑或+1然后错的酸爽,然后赶紧问

原来并没有什么结论因为一些点已经被放了

然后就只能暴力计算sg的值,可以使用Trie树搞一搞,然后膜了一下huzecong的题解

……

//coder : davidwang
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <deque>
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 = 100010,Log=17;
struct node{
	int lch,rch,d,flag;
}s[N*Log*2];
#define l(x) s[x].lch
#define r(x) s[x].rch
int root[N],sg[N],vis[N],sum[N],up[N],fa[N],n,a[N],cnt,tot,ans[N];
vector<int>g[N];
inline int reverse(int x){
	int ret=0;
	for (int i=1;i<=Log;i++)
		if (x>>i-1&1) ret+=1<<Log-i;
	return ret;
}
inline void push_up(int x){
	s[x].flag=s[l(x)].flag && s[r(x)].flag;
}
inline void push_down(int x){
	if (s[x].d){
		if (l(x)) s[l(x)].d^=s[x].d>>1;
		if (r(x)) s[r(x)].d^=s[x].d>>1;
		if (s[x].d&1) swap(l(x),r(x));
		s[x].d=0;
	}
}
inline int getans(int x){
	int ret=0;
	for (int i=Log;x;i--){
		push_down(x);
		if (s[l(x)].flag){
			ret+=1<<i-1;
			x=r(x);
		}else x=l(x);
	}
	return ret;
}
inline void insert(int x,int num,int d){
	push_down(x);
	if (num>>d-1&1){
		if (r(x)==0) r(x)=++cnt;
		if (d!=1) insert(r(x),num,d-1);
		else s[r(x)].flag=1;
	}else{
		if (l(x)==0) l(x)=++cnt;
		if (d!=1) insert(l(x),num,d-1);
		else s[l(x)].flag=1;
	}
	push_up(x);
}
int merge(int l,int r){
	if (l==0 || s[r].flag) return r;
	if (r==0 || s[l].flag) return l;
	push_down(r); push_down(l);
	int now = ++cnt;
	l(now)=merge(l(l),l(r));
	r(now)=merge(r(l),r(r));
	push_up(now);
	return now;
}
inline void init()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	n=read();
	for (int i=1;i<=n;i++) a[i]=read();
	for (int i=1;i<n;i++){
		int x=read(),y=read();
		g[x].push_back(y);
		g[y].push_back(x);
	}
	for (int i=1;i<=n;i++){
		root[i]=++cnt;
	}
}
inline void dfs(int x){
	for (vector<int>::iterator it=g[x].begin();it!=g[x].end();it++){
		if (*it==fa[x]) continue;
		fa[*it]=x;
		dfs(*it);
		sum[x]^=sg[*it];
	}
	for (vector<int>::iterator it=g[x].begin();it!=g[x].end();it++){
		if (*it==fa[x]) continue;
		s[root[*it]].d^=reverse(sg[*it]^sum[x]);
		root[x]=merge(root[x],root[*it]);
	}
	if (a[x]==0) insert(root[x],sum[x],Log);
	sg[x]=getans(root[x]);
}
inline void calc(int x){
	if ((up[x]^sum[x])==0 && a[x]==0) ans[++tot]=x;
	for (vector<int>::iterator it=g[x].begin();it!=g[x].end();it++){
		if (*it==fa[x]) continue;
		up[*it]=up[x]^sum[x]^sg[*it];
		calc(*it);
	}
	return;
}
inline void print()
{
	if (tot==0){ puts("-1"); return ;}
	sort(ans+1,ans+tot+1);
	for (int i=1;i<=tot;i++){
		printf("%d\n",ans[i]);
	}
}
int main()
{
	init();
	dfs(1);
//	for (int i=1;i<=n;i++) printf("%d\n",sg[i]);
	calc(1);
	print();
	return 0;
}

 

 

6
14
2015
0

bzoj 4129: Haruna’s Breakfast

首先改成待修该的树上莫队,然后就发现题目变成了一个要求维护一个集合,加入一个数字,修改一个数字(这两个操作要求O(1)完成)然后询问这个集合的mex值 $$ O(n^{2/3}) $$ 以内完成

然后我想了半天发现修改可以用树状数组,询问可以二分,然后这么又非常逗比的想到了分块大法好这样询问就是$$ O(n^{0.5}) $$ 了

//coder : davidwang
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <ctime>
#include <iostream>
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 = 50010;
int start[N],to[N<<1],next[N<<1],cnt;
int stack[N],bel[N],dfn[N],p[N][20],d[N],fa[N],now,tot,top,col[N];
int a[N],vis[N],n,m,t1,t2;
int block[N],num[N],g[N],l[N],r[N],B,C,D;
int ans[N];
struct query{
	int x,y,t,pos;
	int operator < (const query &A) const {
		if (bel[x]!=bel[A.x]) return bel[x]<bel[A.x];
		if (bel[y]!=bel[A.y]) return bel[y]<bel[A.y];
		return t<A.t;
	}
}Q[N];
struct modify{
	int x,y,pre;
}A[N];
inline void connect(int x,int y){
	to[++cnt]=y; next[cnt]=start[x]; start[x]=cnt;
}
void dfs(int x){
	dfn[x]=++now;
	int bot=top;
	for (int p=start[x];p;p=next[p]){
		int &y=to[p];
		if (y==fa[x]) continue;
		fa[y]=x;  
		d[y]=d[x]+1;
		dfs(y);
		if (top-bot>B){
			tot++;
			while (top>bot) bel[stack[top--]]=tot;
			bel[stack[top--]]=tot;
		}
	}
	stack[++top]=x;
}
int 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++) col[i]=a[i]=read();
	for (int i=1;i<n;i++){
		int x=read(),y=read();
		connect(x,y);
		connect(y,x);
	}
	B = pow(n,2.0/3),C=sqrt(n),D=(n+1)/C+((n+1)%C!=0);
	for (int i=0;i<D;i++){
		l[i]=i*C; r[i]=min(n,(i+1)*C-1);
	}
	d[1]=1;
	dfs(1); tot++;
	while (top) bel[stack[top--]]=tot;
	for (int i=1;i<=m;i++){
		int op=read(),x=read(),y=read();
		if (op==0){
			A[++t2].x=x;
			A[t2].y=y; A[t2].pre=col[x];
			col[x]=y;
		}else{
			t1++;
			if (dfn[x]>dfn[y]) swap(x,y);
			Q[t1].x=x; Q[t1].y=y;
			Q[t1].pos=t1; Q[t1].t=t2;
		}
	}
	sort(Q+1,Q+t1+1);
	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];
	return 0;
} 
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 reverse(int x){
	if (vis[x]){
		vis[x]=0;
		if (a[x]>n) return;
		num[a[x]]--;
		if (num[a[x]]==0){
			g[a[x]/C]--;
		}
	}else{
		vis[x]=1;
		if (a[x]>n) return;
		num[a[x]]++;
		if (num[a[x]]==1){
			g[a[x]/C]++;
		}
	}
}
inline int getans(){

	for (int i=0;i<D;i++){
		if (g[i]==r[i]-l[i]+1) continue;
		for (int j=l[i];j<=r[i];j++){
			if (num[j]==0) return j;
		}
	}

//	for (int i=0;;i++) if (num[i]==0) return i;
	return n;
}
inline void change(int x,int y){
	if (vis[x]){
		reverse(x);
		a[x]=y;
		reverse(x);
	}else a[x]=y;
}
inline void solve(int x,int y){
	while (x!=y){
		if (d[x]>d[y]) reverse(x),x=fa[x];
		else reverse(y),y=fa[y];
	}
}
void work()
{
	for (int i=1;i<=Q[1].t;i++) change(A[i].x,A[i].y);
	solve(Q[1].x,Q[1].y); 
	int u=lca(Q[1].x,Q[1].y); 
	reverse(u); ans[Q[1].pos]=getans(); reverse(u);
	for (int i=2;i<=t1;i++){
		if (Q[i].t>Q[i-1].t) for (int j=Q[i-1].t+1;j<=Q[i].t;j++) change(A[j].x,A[j].y);
		if (Q[i].t<Q[i-1].t) for (int j=Q[i-1].t;j>Q[i].t;j--) change(A[j].x,A[j].pre);
		u=lca(Q[i].x,Q[i].y);
		solve(Q[i].x,Q[i-1].x);
		solve(Q[i].y,Q[i-1].y);
		reverse(u);
		ans[Q[i].pos]=getans();
		reverse(u);
	}
	for (int i=1;i<=t1;i++)
		printf("%d\n",ans[i]);
	return;
}
int main()
{
	init();
	work();
	return 0;
}

 

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
6
2015
0

百度之星2015复赛滚粗记

大家……都能做出第三题来

T1: 给你n个和x、y轴平行的线段,问能够构成多少长方形n<=25,T<=100

这……就是四重循环让然后看一下就好

 

T2 : 给你一个吉他谱,然后让你找一个最方便的和弦转换方式使每个手指移动的距离和最小(题面竟然是错的!花了半天来理解样例才发现)

n<=5000 然后就是暴力dp写起来挺难受的

这两到2b题目就不放代码了

T3:给你一个图,每条边的权值是一个字符串,求字典序最小的路径N<=50,M<=500,len<=6

我写完第一道题(10min)的样子,然后看着道题目有人过了,于是就开坑了……然后被坑的好惨

一直在挂从未被超越

我的想法是对于每条边查成len+1个点和len条边这样每个边的边权都是1个字母然后我们枚举最大的字母寻找是否存在路径,如果存在路径那么输出,如果这里存在一个环,环上的点可以通过更大的字母联通到终点那么就是toughway。但是这样又有一个很难受的例子

4 4 0 3

0 1 aaa

1 2 aaa

0 2 aaaaa

2 3 b

然后这就是aaaaaab是答案,但是这样搞出来是aaaaab然后……算了,反正我这种蒟蒻
 

T4:

给你一个环,环上有n个n等分点,每个点有高度,选择两个点,高度之和加上两个点环上的最短距离最大,然后输出字典序最小的一对点。

环上问题改成链上复制一遍,每个点变成i的全职是高度加上等分距离*i。然后反正就是线段树查询区间最大值,然后注意字典序最小的时候要考虑环右边复制的字典序要比左边小。然后因为这个Wa了一发

//coder : davidwang
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <ctime>
#include <vector>
#include <deque>
#include <queue>
#include <string>
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 = 200010;
struct node{
	int l,r;
	inline int mid(){ return r+l>>1; }
	int mp;
}s[N<<2];
LL a[N],h[N],R;
int n;
inline int get(int x){
	return x>n?x-n:x;
}
inline void push_up(int x){
	int A=s[x<<1].mp,B=s[x<<1|1].mp;
	s[x].mp=a[A]>a[B] || (a[A]==a[B] && get(A)<get(B))?A:B;
}
inline void build(int i,int l,int r){
	s[i].l=l; s[i].r=r;
	if (l==r){
		s[i].mp=l;
		return;
	}
	int m=l+r>>1;
	build(i<<1,l,m);
	build(i<<1|1,m+1,r);
	push_up(i);
}
inline int query(int i,int l,int r){
	if (s[i].l==l && s[i].r==r) return s[i].mp;
	int m=s[i].mid();
	if (r<=m) return query(i<<1,l,r);
	else if (l>m) return query(i<<1|1,l,r);
	else{
		int A=query(i<<1,l,m),B=query(i<<1|1,m+1,r);
		return a[A]>a[B] || (a[A]==a[B] && get(A)<get(B))?A:B;
	}
}
inline void work(){
	LL cur=0;
	int al,ar;
	for (int i=1;i<=n;i++){
		int j=query(1,i+1,i+n/2);
		LL tmp=a[j]-i*R+h[i];
		int ll=i,rr=j;
		if (rr>n) rr-=n,swap(ll,rr);
		if (tmp>cur){
			cur=tmp;
			al=ll; ar=rr;
		}else if (tmp==cur && (ll<al || (ll==al && rr<ar))){
			al=ll; ar=rr;
		}
	}
	printf("%d %d\n",al,ar);
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	int T=read();
	for (int tt=1;tt<=T;tt++){
		printf("Case #%d:\n",tt);
		n=read(); R=read();
		for (int i=1;i<=n;i++){
			h[i]=read();
			a[i]=R*(LL)i+h[i];
		}
		for (int i=n+1;i<=2*n;i++){
			a[i]=i*R+h[i-n];
		}
		build(1,1,2*n);
		work();
	}
	return 0;
}

 

T5:

意思是给你一个字符串,找到最短的不是这个字符串子序列的字符串,然后问有多少个

一开始看错题了,以为是cf461E后来发现不对这里的子序列不是连续的(不是子串)选取规则也不一样

然后就非常水了

Dp[i]表示一个二元组表示我们现在匹配到了第i个位置,最少使用多少个字符,有多少种方案

然后转移是一个区间[pre[i],i-1](这里的pre[i]表示i前面和相同的字母出现的最后位置),可以用线段树优化(有一道线段树题目)

//coder : davidwang
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <ctime>
#include <vector>
#include <deque>
#include <queue>
#include <string>
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 = 100010,mod=1000000007;
struct Ans{
	int len,way;
	Ans(int x=0,int y=0): len(x),way(y){}
}now;
inline Ans min(const Ans &a,const Ans &b){
	if (a.len<b.len) return a;
	else if (a.len>b.len) return b;
	else return Ans(a.len,(a.way+b.way)%mod);
}
struct node{
	int l,r;
	inline int mid(){ return r+l>>1; }
	Ans A;
}s[N<<2];
inline void push_up(int x){
	s[x].A=min(s[x<<1].A,s[x<<1|1].A);
}
inline void build(int i,int l,int r){
	s[i].l=l; s[i].r=r;
	if (l==r){
		return;
	}
	s[i].A=Ans(N,0);
	int m=l+r>>1;
	build(i<<1,l,m); build(i<<1|1,m+1,r);
}
inline Ans query(int i,int l,int r){
	if (l>r) return Ans(N,0);
	if (s[i].l==l && s[i].r==r) return s[i].A;
	int m=s[i].mid();
	if (r<=m) return query(i<<1,l,r);
	else if (l>m) return query(i<<1|1,l,r);
	else return min(query(i<<1,l,m),query(i<<1|1,m+1,r));
}
inline void modify(int i,int p){
	if (s[i].l==s[i].r){
		s[i].A=now;
		return;
	}
	if (p<=s[i].mid()) modify(i<<1,p);
	else modify(i<<1|1,p);
	push_up(i);
}
int last[26],a[N],pre[N];
char st[N];
int main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	int T=read();
	for (int tt=1;tt<=T;tt++){
		printf("Case #%d:\n",tt);
		scanf("%s",st+2);
		st[1]='.';
		int n=strlen(st+1);
		build(1,1,n);	
		now=Ans(0,1);
		modify(1,1);
		for (int i=0;i<26;i++) last[i]=1;
		for (int i=2;i<=n;i++){
			a[i]=st[i]-'a';
			pre[i]=last[a[i]];
			last[a[i]]=i;
		}
		for (int i=2;i<=n;i++){
			now=query(1,pre[i],i-1);
			now.len++;
			modify(1,i);
		}
		Ans ans=Ans(N,0);
		for (int i=0;i<26;i++){
			ans=min(ans,query(1,last[i],n));
		}
		printf("%d %d\n",ans.len+1,ans.way);
	}
	return 0;
}

 

T6看了以下完全不会

给你一个n个点m条边的有向图让你删去最多k条边,使得每个点的入读和初度的绝对值的最大值最小

n<=50 k<=m<=n*(n-1)

不会!

似乎有一点网络流的感觉但是这么少的人做出来应该不会是网络流吧。。。

 

 

 

Category: 未分类 | Tags: 游记

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