hdu5584LCM Walk(上海现场赛L题)

题意:规定LCM走法:假设现在在(x,y)点,则可以走到(x,y+lcm(x,y))或(x+lcm(x,y),y)两个点。给你一个点,问能有多少个起点走到(x,y)。

比赛的时候看到1e9根本不敢搜,后来还是学长想出了做法。

假设能从(x,y')走到(x,y),那么y'一定是y的约数,暴力枚举所有的约数判断能否走到(x,y)就好了。复杂度O(sqrt(n)*log(n)*log(n))。

#include<cstdio>
int t,x,y,ans;
int gcd(int a,int b)
{
	if (b==0) return a;
	else return gcd(b,a%b);
}
long long lcm(int a,int b)
{
	return (long long )a*b/gcd(a,b);
}
void dfs(int x,int y)
{
	ans++;
	for (int i=1;i*i<=x;i++)
		if (x%i==0)
		{
			int j=x/i;
			if (i+lcm(i,y)==x) dfs(i,y);
			if (j!=i&&j+lcm(j,y)==x) dfs(j,y);
		}
	for (int i=1;i*i<=y;i++)
		if (y%i==0)
		{
			int j=y/i;
			if (i+lcm(x,i)==y) dfs(x,i);
			if (j!=i&&j+lcm(x,j)==y) dfs(x,j);
		}
}
int main()
{
	scanf("%d",&t);
	for (int cas=1;cas<=t;cas++)
	{
		scanf("%d%d",&x,&y);
		ans=0;
		dfs(x,y);
		printf("Case #%d: %d\n",cas,ans);
	}
}

hdu5573Binary Tree(dfs)(上海现场赛B题)

这道题当时的idea是我想出来的,ACalvin学长听完我的思路后直接上,1A,印象深刻!

题意就是说从一个深度为k的完全二叉树,找一条根到叶子节点的路径,使得它们的编号能够通过加减法得到N。

我的做法是枚举叶子节点往上dfs,发现如果当前的值小于N,就必须加上当前的编号才有可能达到N,同理,如果当前的值大于N,就必须减去当前的编号才有可能达到N。

当时感觉枚举几个就会很快得到答案,心里还是有点虚的,1A的时候真是兴奋啊。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long a[100],b[100];
int n,k;
bool dfs(long long sum,long long now,int d)
{
	if (d==0)
	{
		if (now==0&&sum==n) return 1;
		else return 0;
	}
	if (sum<n) a[d]=now,b[d]=1,dfs(sum+now,now/2,d-1);
	else a[d]=now,b[d]=0,dfs(sum-now,now/2,d-1);
}
int main()
{
	int t;
	scanf("%d",&t);
	for (int cas=1;cas<=t;cas++)
	{
		scanf("%d%d",&n,&k);
		for (long long i=1<<(k-1);;i++)
			if (dfs(0,i,k)) break;
		printf("Case #%d:\n",cas);
		for (int i=1;i<=k;i++)
			printf("%d ",a[i]),printf(b[i]?"+\n":"-\n");

	}
}

hdu4912-Paths on the tree(2014 Multi-University Training Contest 5)

题意:给你一棵树,和m条链,问最多能取多少条没有公共点的链。

这道题的加强版出现在15年的多校第1场,见hdu5293,加强版每条链还有权值。

因为我是先做了加强版(当时坑了一天),看到这道题,于是直接树形dp了。。。。(标算是贪心。。。)

每个节点u维护两个值:1.f[u]表示u所在子树最多有几条链   2.sum[u]表示u的子节点的f值的和

sum[u]很好搞,f[u]的转移方法如下:

假设有一条链x,y|lca(x,y)==u

f[u]=max(sum[u],sigma(sum[v])-sigma(f[v])+1)

其中v是链上的点

简单的说就是:

1.不要这条链,f[u]就是sum[u]

2.要这条链,那么f[u]=这条链下面的所有子树能够选择的链的个数+1

链上求和的话可以用树状数组或者线段树维护dfs序,每个点记录根到该点路径上的和,每修改一个点就是把其子树里点的值都加上f[u]或sum[u].

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=100005;
int base[N],vec[2*N],pre[2*N],tot;

struct pair{
	int x,y;
}to[N];
int head[N],nxt[N],total;

int fa[N][25],deep[N];
int dfn[N],time,l[N],r[N];
int cf[N],cs[N];
int f[N],sum[N];
int n,m,x,y,i;
void addf(int x,int k)
{
    for (int i=x;i<=n;i+=i&-i) cf[i]+=k;
}
void addsum(int x,int k)
{
    for (int i=x;i<=n;i+=i&-i) cs[i]+=k;
}
int getf(int x)
{
    int tmp=0;
    for (int i=x;i;i-=i&-i) tmp+=cf[i];
    return tmp;
}
int getsum(int x)
{
    int tmp=0;
    for (int i=x;i;i-=i&-i) tmp+=cs[i];
    return tmp;
}
void push(int u,int x,int y)
{
	to[++total]={x,y}; nxt[total]=head[u];  head[u]=total;
}
void link(int x,int y)
{
	vec[++tot]=y;  pre[tot]=base[x];  base[x]=tot;
}
int lca(int x,int y)
{
	if (deep[x]<deep[y]) swap(x,y);
	if (deep[x]>deep[y])
		{
			for (int j=20;j>=0;j--)
				if (deep[fa[x][j]]>deep[y]) x=fa[x][j];
			x=fa[x][0];
		}
	if (x==y) return x;
	for (int j=20;j>=0;j--)
		if (fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
	return fa[x][0];
}
void dfs1(int u)
{
	dfn[u]=++time;
	l[u]=time;
	for (int now=base[u];now;now=pre[now])
	{
		int v=vec[now];
		if (v!=fa[u][0])
		{
			fa[v][0]=u;
			deep[v]=deep[u]+1;
			dfs1(v);
		}
	}
	r[u]=time;
}
void dfs2(int u)
{
	sum[u]=0;
	for (int now=base[u];now;now=pre[now])
	{
		int v=vec[now];
		if (v!=fa[u][0])
		{
			dfs2(v);
			sum[u]+=f[v];
		}
	}
	f[u]=sum[u];
	for (int i=head[u];i;i=nxt[i])
	{
		int x=dfn[to[i].x],y=dfn[to[i].y];
		f[u]=max(f[u],getsum(x)+getsum(y)+sum[u]-getf(x)-getf(y)+1);
	}
	addf(l[u],f[u]);
	addf(r[u]+1,-f[u]);
	addsum(l[u],sum[u]);
	addsum(r[u]+1,-sum[u]);
}
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		time=0;
		tot=0;  total=0;
		memset(head,0,sizeof(head));
		memset(base,0,sizeof(base));
		memset(cf,0,sizeof(cf));
		memset(cs,0,sizeof(cs));
		for (i=1;i<n;i++) scanf("%d%d",&x,&y),link(x,y),link(y,x);
		fa[1][0]=1;  deep[1]=1;
		dfs1(1);
		for (int j=1;j<=20;j++)
			for (i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1];
		for (i=1;i<=m;i++)
		{
			scanf("%d%d",&x,&y);
			push(lca(x,y),x,y);
		}
		dfs2(1);
		printf("%d\n",f[1]);
	}
}

贪心做法:

将链按lca的深度排序,从深度大的开始,能取就取,取完后把该链下的子树全部标记,因此每次判断能否取就是O(1)的.(竟然跑的比上面的方法慢?!)

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=100005;
int base[N],vec[2*N],pre[2*N],tot;

struct chain{
	int x,y,u;
}a[N];
int fa[N][25],deep[N];
bool vis[N];
bool cmp(chain a,chain b) {return deep[a.u]>deep[b.u];}
int n,m,x,y,i;
void link(int x,int y)
{
	vec[++tot]=y;  pre[tot]=base[x];  base[x]=tot;
}
int lca(int x,int y)
{
	if (deep[x]<deep[y]) swap(x,y);
	if (deep[x]>deep[y])
		{
			for (int j=20;j>=0;j--)
				if (deep[fa[x][j]]>deep[y]) x=fa[x][j];
			x=fa[x][0];
		}
	if (x==y) return x;
	for (int j=20;j>=0;j--)
		if (fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
	return fa[x][0];
}
void dfs(int u)
{
	for (int now=base[u];now;now=pre[now])
	{
		int v=vec[now];
		if (v!=fa[u][0])
		{
			fa[v][0]=u;
			deep[v]=deep[u]+1;
			dfs(v);
		}
	}
}
void clean(int u)
{
	if (vis[u]) return;
	vis[u]=1;
	for (int now=base[u];now;now=pre[now])
	{
		int v=vec[now];
		if (v!=fa[u][0]) clean(v);
	}
}
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		tot=0;
		memset(base,0,sizeof(base));
		memset(vis,0,sizeof(vis));
		for (i=1;i<n;i++) scanf("%d%d",&x,&y),link(x,y),link(y,x);
		fa[1][0]=1;  deep[1]=1;
		dfs(1);
		for (int j=1;j<=20;j++)
			for (i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1];
		for (i=1;i<=m;i++)
		{
			scanf("%d%d",&a[i].x,&a[i].y);
			a[i].u=lca(a[i].x,a[i].y);
		}
		sort(a+1,a+m+1,cmp);
		int ans=0;
		for (i=1;i<=m;i++)
			if (!vis[a[i].x]&&!vis[a[i].y])
			{
				clean(a[i].u);
				ans++;
			}
		printf("%d\n",ans);
	}
}

ZOJ-3209 dancinglink模板题

题意:用p(500)个矩形(给出左下角和右上角)拼成一个n×m(30×30)的大矩形,输出最少使用个数。

把n×m每个格子都看成交叉十字循环双向链的一列,于是有n×m列,每个矩形都覆盖了一些列,于是就转化成01矩阵的精确覆盖,直接上模板。

建图的时候注意细节

#include<cstdio>
const int N=505005,INF=0x3f3f3f3f;
struct DLX
{
    int L[N],R[N],U[N],D[N],row[N],col[N];
    int H[505];
    int ansd,ans[505];
    int s[1005];
    int tot,n,m;
    void init(int _n,int _m)
    {
    	n=_n;  m=_m;
    	tot=m;
    	for (int i=0;i<=m;i++) L[i]=i-1,R[i]=i+1,U[i]=i,D[i]=i,s[i]=0;
    	L[0]=m;  R[m]=0;
    	for (int i=1;i<=n;i++) H[i]=-1;
    }
    void link(int i,int j)
    {
    	s[j]++;
    	++tot;
    	row[tot]=i;  col[tot]=j;

    	U[tot]=U[j];  D[tot]=j;  D[U[j]]=tot;	U[j]=tot;
    	if (H[i]<0)
		{
			H[i]=tot; L[tot]=tot; R[tot]=tot;
		}
		else
		{
			L[tot]=L[H[i]];  R[tot]=H[i]; R[L[H[i]]]=tot; L[H[i]]=tot;
		}
    }
    void remove(int c)
    {
        R[L[c]]=R[c];  L[R[c]]=L[c];
        for (int i=D[c];i!=c;i=D[i])
            for (int j=R[i];j!=i;j=R[j])
            {
            	s[col[j]]--;
                D[U[j]]=D[j];
                U[D[j]]=U[j];
            }
    }
    void resume(int c)
    {
    	R[L[c]]=c;	L[R[c]]=c;
        for (int i=U[c];i!=c;i=U[i])
            for (int j=L[i];j!=i;j=L[j])
            {
            	s[col[j]]++;
                D[U[j]]=j;
                U[D[j]]=j;
            }
    }
    void dfs(int d)
    {
    	if (d-1>=ansd) return ;
        if (R[0]==0)
        {
            if (d-1<ansd) ansd=d-1;
            return;
        }
        int c=R[0];
        for (int i=R[0];i!=0;i=R[i])
			if (s[i]<s[c]) c=i;
        remove(c);
        for (int i=D[c];i!=c;i=D[i])
        {
        	ans[d]=row[i];
            for (int j=R[i];j!=i;j=R[j]) remove(col[j]);
            dfs(d+1);
            for (int j=L[i];j!=i;j=L[j]) resume(col[j]);
        }
        resume(c);
        return;
    }
}g;
int main()
{
	int t;
	int n,m,p,sx,sy,ex,ey;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d%d",&n,&m,&p);
		g.init(p,n*m);
		for (int k=1;k<=p;k++)
		{
			scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
			for (int i=sx+1;i<=ex;i++)
				for (int j=sy+1;j<=ey;j++) g.link(k,(i-1)*m+j);
		}
		g.ansd=INF;
		g.dfs(1);
		if (g.ansd<INF) printf("%d\n",g.ansd);
		else printf("-1\n");
	}
}

 

 

学习清单-zjhl2

 

  • 字符串

  1. AC自动机
  2. 后缀数组
  • 数据结构

  1. 平衡树

  • 图论

  1. 最小割

  2. 费用流

  3. 树链剖分

  4. 动态树

  • 计算几何

  1. 半平面交

  2. 坐标旋转

  3. 旋转卡壳

  4. 扫描线

  • 搜索

  1. 双向bfs
  2. IDA×
  3. dancing link
  • 动态规划

  1. 插头dp
  • 数学

  1. lucas

  2. 扩展欧几里得

  3. FFT

  4. 博弈

  5. 概率

hdu1077-单位圆覆盖最多点

做计算几何好苦。。。。。。

题意:用半径为1的圆覆盖最多的点

枚举两个点构造出圆使得这两点在圆上,判断覆盖了多少点。复杂度O(n^3)

一直WA,以为是被卡精度了,后来看了kuangbin的题解才知道忘记考虑n==1时答案为1的情况,思维有缺陷,思维品质不高啊。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#define eps 1e-4
using namespace std;
int t,n,i,j;
struct dot{
    double x,y;
}a[305];
double sqr(double x){return x*x;}
double dis(double ax,double ay,double bx,double by)
{
    return sqrt(sqr(ax-bx)+sqr(ay-by));
}
int get(double x,double y)
{
    int cnt=0;
    for (int i=1;i<=n;i++)
        if (dis(x,y,a[i].x,a[i].y)<=1+eps) cnt++;
    return cnt;
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for (i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y);
        int ans=1;
        for (i=1;i<n;i++)
            for (j=i+1;j<=n;j++)
            {
                double d=dis(a[i].x,a[i].y,a[j].x,a[j].y)/2;
                if (d>1) continue;
                double sita=acos(d);
                double ang=atan2(a[j].y-a[i].y,a[j].x-a[i].x);
                double x=a[i].x+cos(ang-sita),y=a[i].y+sin(ang-sita);
                ans=max(ans,get(x,y));
                x=a[i].x+cos(ang+sita);y=a[i].y+sin(ang+sita);
                ans=max(ans,get(x,y));
            }
        printf("%d\n",ans);
    }
}

(转)菜鸟,大牛,教主的区别

对菜鸟来说题目有三种:会算法且能AC的,会算法但不能AC的,不会做的

对大牛来说题目有两种:会做的,不会做的

对教主来说题目有两种:能AC的,数据有错的

 

菜鸟提交WA了,找了N久找不出错时,在论坛大骂数据有错,但是没人理

大牛提交WA了,找了N久找不出错时,写暴力程序或者求别人的AC程序对拍

教主提交WA了,Judge马上修正数据

 

菜鸟面对一道难题,直接暴搜

大牛面对一道难题,算了算时间复杂度不对,或者证明出是NP难,果断放弃

教主面对一道难题,说,虽然我不会做,但AC还是没有问题的

 

菜鸟AC了一道难题,巴不得召告天下

大牛AC了一道难题,会写一篇解题报告,第一句话一定是:这题其实不难

教主AC了一道难题,好像什么都没发生过

 

菜鸟切OJ,只挑简单题做

大牛切OJ,成套成套地做

教主早就不切OJ了

 

菜鸟经常在论坛和QQ上求助

大牛经常在论坛和QQ上灌水

教主一般不露面

 

菜鸟喜欢说自己做了几十几百道题

大牛喜欢说自己把某个OJ做了百分之八九十

教主一般不说话


菜鸟队看到场上90%的队伍挂起了红球,开始找红球是哪道题

大牛队全场第一个挂起黄球,然后发现几乎同时有另外几支大牛队也挂起了黄球

教主队全场第一个挂起绿球,然后全场到最后也只有一个绿球

 

菜鸟喜欢搜集各种模板

大牛只用自己写的模板

教主不用模板,但他当场写的程序会被别人用作模板


菜鸟喜欢YY这种分析菜鸟、大牛和教主的区别的文章

大牛看完这样的文章会笑一笑,懒得回帖

教主直接无视

 

hdu5572 An Easy Physics Problem(2015上海区域赛A题)

刚开始做计算几何,就拿之前上海区域赛的题目来练练吧。

比赛的时候看了题意,是haipz学长做的,当时感觉这是一道依靠模板的题目。

现在做了下,发现其实可以这么做:

1.旋转坐标,把速度方向搞成x轴正方向

2.可以直接比较Ay和r判断是否碰到圆柱。如果没碰到,直接判断射线能否到达B;如果碰到圆柱,可以直接勾股定理计算出碰撞点的坐标,然后就可以用atan2(y,x)函数求出反射方向的弧度,这时只要判断反射方向的弧度和碰撞点到B的向量的弧度是否相等就好了

注意判断弧度相等的时候别忘了考虑两弧度相减等于2pi的情况,所以我是用三角函数判断两弧度相等

#include<cstdio>
#include<iostream>
#include<cmath>
#define pi acos(-1)
#define eps 1e-3
using namespace std;
int t;
double ax,ay,bx,by,vx,vy,rx,ry,jx,jy,r;
void rotate(double &sx,double &sy,double sita)
{
    double x=sx,  y=sy;
    sx=x*cos(sita)+y*sin(sita);
    sy=y*cos(sita)-x*sin(sita);
}
void move()
{
    ax-=rx;  bx-=rx;
    ay-=ry;  by-=ry;
    rx=ry=0;
    double x,y;
    double sita=atan2(vy,vx);
    rotate(ax,ay,sita);
    rotate(bx,by,sita);
    rotate(vx,vy,sita);
    if (ay<-eps)
    {
        vy=-vy;
        ay=-ay;
        by=-by;
    }
}
bool bounce()
{
    return ay<r&&ax<0;
}
bool shoot()
{
    return fabs(ay-by)<eps&&bx>ax;
}
bool equ(double a,double b)
{
    return fabs(sin(a)-sin(b))<eps&&fabs(cos(a)-cos(b))<eps;
}
bool hit()
{
    if (!bounce())
        return shoot();
    //bounce
    if (shoot()) return bx<0;
    jy=ay;
    jx=-sqrt(r*r-ay*ay);
    double sita=atan2(jy,jx);
    sita=pi-sita;
    sita=pi-sita*2;
    return equ(atan2(by-jy,bx-jx),sita);
}
int main()
{
    scanf("%d",&t);
    int cas=0;
    while(t--)
    {
        scanf("%lf%lf%lf",&rx,&ry,&r);
        scanf("%lf%lf%lf%lf",&ax,&ay,&vx,&vy);
        scanf("%lf%lf",&bx,&by);
        move();
        //printf("%f %f %f\n",rx,ry,r); printf("%f %f %f %f\n",ax,ay,vx,vy);printf("%f %f\n",bx,by);
        printf("Case #%d: ",++cas);
        if (hit()) printf("Yes\n");else printf("No\n");
    }
}

java 重定向

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.Scanner;
public class Main {
	public static void main(String[] args)throws FileNotFoundException  
	{
		
		FileInputStream fis = new FileInputStream("input.txt");
		System.setIn(fis);
		
		PrintStream ps = new PrintStream(new FileOutputStream("output.txt"));
		System.setOut(ps);
		
		Scanner cin=new Scanner(System.in);
		int n;
		
		while(cin.hasNext())
		{
			n=cin.nextInt();
			System.out.println(n);
		}
	}

}

POJ2135最小费用最大流

第一次写费用流,仔细想过后也不过是这么回事。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1005,M=10020,INF=0x3f3f3f3f;
int n,m;
struct G{
	int base[N],vec[4*M],pre[4*M],cost[4*M],flow[4*M],tot;
	int S,T;
	int mincost,maxflow;
	int dis[N],que[N];
	int pv[N],pe[N];
	bool vis[N];
	void link(int x,int y,int z,int f)
	{
		vec[++tot]=y;  pre[tot]=base[x];  base[x]=tot; cost[tot]=z; flow[tot]=f;
		vec[++tot]=x;  pre[tot]=base[y];  base[y]=tot; cost[tot]=-z; flow[tot]=0;
	}
	void build()
	{
		memset(base,0,sizeof(base));
		tot=1;
		int x,y,z;
		scanf("%d%d",&n,&m);
		for (int i=1;i<=m;i++)
		{
			scanf("%d%d%d",&x,&y,&z);
			link(x,y,z,1);
			link(y,x,z,1);
		}
		S=0;  T=n+1;
		link(S,1,0,2);
		link(n,T,0,2);
	}
	bool spfa()
	{
		memset(vis,0,sizeof(vis));
		memset(pv,-1,sizeof(pv));
		memset(dis,0x3f3f3f3f,sizeof(dis));
		int head=0,tail=1;
		que[tail]=S;  vis[S]=1;  dis[S]=0;
		while(head!=tail)
		{
			head++;
			head%=N;
			int u=que[head];
			vis[u]=0;

			for (int now=base[u];now;now=pre[now])
			if (flow[now]>0)
			{
				int v=vec[now];
				if (dis[u]+cost[now]<dis[v])
				{
					dis[v]=dis[u]+cost[now];
					pv[v]=u;
					pe[v]=now;
					if (!vis[v])
					{
						vis[v]=1;
						tail++;
						tail%=N;
						que[tail]=v;
					}
				}
			}
		}
		if (dis[T]!=INF) return 1;else return 0;
	}
	void work()
	{
		mincost=0;
		maxflow=0;
		while(spfa())
		{
			int mxf=INF;
			mincost+=dis[T];
			for (int v=T;v!=S;v=pv[v])
				mxf=min(mxf,flow[pe[v]]);
			maxflow+=mxf;
			for (int v=T;v!=S;v=pv[v])
				flow[pe[v]]-=mxf,flow[pe[v]^1]+=mxf;
		}
	}
}g;
int main()
{
	g.build();
	g.work();
	printf("%d\n",g.mincost);
}