比赛 (long double 与fixed)

比赛

 (mat.pas/c/cpp)

【问题描述】

    有两个队伍A和B,每个队伍都有n个人。这两支队伍之间进行n场1对1比赛,每一场都是由A中的一个选手与B中的一个选手对抗。同一个人不会参加多场比赛,每个人的对手都是随机而等概率的。例如A队有A1和A2两个人,B队有B1和B2两个人,那么(A1 vs B1,A2 vs B2)和(A1 vs B2,A2 vsB1)的概率都是均等的50%。

    每个选手都有一个非负的实力值。如果实力值为X和Y的选手对抗,那么实力值较强的选手所在的队伍将会获得(X-Y)^2的得分。

    求A的得分减B的得分的期望值。

【输入格式】

    第一行一个数n表示两队的人数为n。

    第二行n个数,第i个数A[i]表示队伍A的第i个人的实力值。

    第三行n个数,第i个数B[i]表示队伍B的第i个人的实力值。

【输出格式】

    输出仅包含一个实数表示A期望赢B多少分。答案保留到小数点后一位(注意精度)

【样例输入】

    2

    37

    15

【样例输出】

    20.0

【数据规模】

    对于30%的数据,n≤50。

    对于100%的.据,n≤50000;A[i],B[i]≤50000。

 

∑(a[i]-b[i))^2

注意后缀数要在排序后T_Y

另外C++要用long double ---但是不能用.lf占位符

要用如下的格式

cout.setf(ios::fixed);
	cout.precision(1);



	cout<<ans/n<<endl;

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<functional>
#include<algorithm>
#include<iostream>
using namespace std;
#define MAXN (50000+10)
long long n,a[MAXN],b[MAXN],sumb[MAXN],sumb2[MAXN];
int main()
{
    freopen("mat.in","r",stdin);
    freopen("mat.out","w",stdout);

    scanf("%d",&n);
    sumb[0]=sumb2[0]=0;
    for (int i=1;i<=n;i++)
    {
        cin>>a[i];
	}
    sort(a+1,a+1+n);
	for (int i=1;i<=n;i++)
    {
        cin>>b[i];
}
    sort(b+1,b+1+n);

	for (int i=1;i<=n;i++)
	{
		sumb[i]=sumb[i-1]+b[i];
        sumb2[i]=sumb2[i-1]+b[i]*b[i];
	}


	long double ans=0.0;


	for (int i=1;i<=n;i++) cout<<sumb[i]<<' ';
	cout<<endl;
	int r=0;
    for (int i=1;i<=n;i++)
    {
        while (r<n&&a[i]>b[r+1]) r++;


        ans+=a[i]*a[i]*(2*r-n);
        ans+=2*sumb2[r]-sumb2[n];

        ans-=2*a[i]*(2*sumb[r]-sumb[n]);

        /*
		long double tmp=0.0;
        //cout<<r<<endl;

		tmp+=r*a[i]*a[i]-2*a[i]*sumb[r]+sumb2[r];
        cout<<tmp<<endl;

		tmp-=(n-r)*a[i]*a[i]-2*a[i]*(sumb[n]-sumb[r])+sumb2[n]-sumb2[r];
        tmp/=n;

        ans+=tmp;


//		cout<<ans;
	*/
    }

//	cout<<ans<<endl;

	cout.setf(ios::fixed);
	cout.precision(1);



	cout<<ans/n<<endl;



//  while (1);
    return 0;
}

祖孙询问 (模拟栈代替DFS)

祖孙询问

(tree.pas/c/cpp)

【问题描述】

    已知一棵n个节点的有根树。有m个询问。每个询问给出了一对节点的编号x和y,询问x与y的祖孙关系。

【输入格式】

    输入第一行包括一个整数n表示节点个数。

    接下来n行每行一对整数对a和b表示a和b之间有连边。如果b是-1,那么a就是树的根。

    第n+2行是一个整数m表示询问个数。

    接下来m行,每行两个正整数x和y。

【输出格式】

    对于每一个询问,输出1:如果x是y的祖先,输出2:如果y是x的祖先,否则输出0。

【样例输入】

10

234 -1

12 234

13 234

14 234

15 234

16 234

17 234

18 234

19 234

233 19

5

234233

23312

23313

23315

23319

【样例输出】

1

0

0

0

2

【数据规模】

    对于30%的数据,n,m≤1000。

    对于100%的.据,n,m≤40000,每个节点的编号都不超过40000。

先看看标准方法求LCA(msm法):

为了处理爆栈而进行各种压缩变量,卡内存过关(边表记得*2)

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<functional>
#include<algorithm>
#include<iostream>
using namespace std;
#define MAXN (80000+10)
/*
#define f( i , j ) f[ ( i ) + 2 , j ]
#define b( i ) b [ ( i ) + 2  ]
*/
int n,m,f[MAXN][100],len[MAXN],deep[MAXN];
int head[MAXN],next[MAXN],edge[MAXN],siz=0;
int log2(int x)
{
    return (int)trunc(log(x)/log(2));
}
void addedge(int u,int v)
{
     edge[++siz]=v;
     next[siz]=head[u];
     head[u]=siz;
}
int a[MAXN]={0},tot=0;
bool b[MAXN];
void dfs(int x,int dep)
{
     /*
     cout<<x<<':';
    for (int i=1;i<=tot;i++) cout<<a[i]<<' ';
    cout<<endl;
    */
    b[x]=1;
    int p=head[x];
    while (p)
    {
         int now=edge[p];
         tot++;
         a[tot]=now;
         if (!b[now]) dfs(now,dep+1);
         tot--;
         p=next[p];
    }
    /*
     cout<<x<<':';
    for (int i=1;i<=tot;i++) cout<<a[i]<<' ';
    cout<<endl;
    */
    int j=0;
    for (int i=tot-1;i>=1;i-=(tot-i))
    {
        f[x][j]=a[i];
        j++;
    }
    len[x]=j-1;
    deep[x]=dep;
}
int father(int x,int y)
{
    while (y)
    {
          int p=log2(y);
          x=f[x][p];
          y-=(1<<p);
    }
    return x;
}
int main()
{
    freopen("tree.in","r",stdin);
  freopen("tree.out","w",stdout);

    memset(head,0,sizeof(head));
    memset(next,0,sizeof(next));
    memset(edge,0,sizeof(edge));
    memset(len,0,sizeof(len));
    memset(b,0,sizeof(b));
    memset(deep,0,sizeof(deep));
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        addedge(x+2,y+2);addedge(y+2,x+2);
    }
    a[1]=1;tot=1;
    dfs(1,0);
    /*
    for (int i=1;i<=n+2;i++)
    {
        cout<<i<<' '<<len[i]<<':';
        for (int j=0;j<=len[i];j++) cout<<f[i][j]<<' ';
        cout<<endl;

    }
    */




    scanf("%d",&m);



    for (int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        x+=2;y+=2;
      //  cout<<x<<' '<<y<<' '<<deep[x]<<' '<<deep[y]<<endl;
        if (x==1) printf("1n");
        else if (y==1) printf("2n");
        else
        {
            int depx=deep[x],depy=deep[y];
            if (depx<depy)
            {
               if (father(y,depy-depx)==x) printf("1n");
               else printf("0n");
            }
            else if (depx>depy)
            {
                 if (father(x,depx-depy)==y) printf("2n");
                 else printf("0n");
            }
            else printf("0n");
        }

    }

  //  while (1);


    return 0;
}

考虑欧拉路径——它可以判断2个节点的从属情况

模拟栈版本:巧用while循环代替dfs

Program tree;
const
   maxn=40000;
   maxm=40000;
var
   n,m,i,j,u,v,size,x,y:longint;
   head,next,edge:array[-1..maxm*2] of longint;
// dfs
   stack:array[1..maxm*10] of longint;
   b:array[-1..maxn] of boolean;
   l,r,father:array[-1..maxn] of longint;
   time,nowstack:longint;
Procedure addedge(u,v:longint);
begin
   inc(size);
   edge[size]:=v;
   next[size]:=head[u];
   head[u]:=size;
end;
Procedure dfs;
var
   i,j,p,now,v:longint;
   flag:boolean;
begin
   time:=0;nowstack:=1;
   stack[1]:=-1;
   while (nowstack>0) do
   begin
      flag:=false;
      now:=stack[nowstack];
      inc(time);

      if not(b[now]) then begin b[now]:=true;l[now]:=time; end;



      p:=head[now];
      while (p>0) do
      begin
         if not(b[edge[p]]) then
         begin
            v:=edge[p];
            father[v]:=now;
            inc(nowstack);
            stack[nowstack]:=v;
            flag:=true;break;
         end;
         p:=next[p];
      end;
      if flag then continue;
      inc(time);  r[now]:=time; dec(nowstack);
   end;
end;
begin
   assign(input,'tree.in');
   assign(output,'tree.out');
   reset(input);
   rewrite(output);
   read(n);
   fillchar(head,sizeof(head),0);
   fillchar(l,sizeof(l),0);
   fillchar(r,sizeof(r),0);
   fillchar(b,sizeof(b),false);
   size:=0;
   for i:=1 to n do
   begin
      read(u,v);
      addedge(u,v); addedge(v,u);
   end;

   dfs;

   read(m);
   for i:=1 to m do
   begin
      read(x,y);
      if (l[x]<l[y]) and (r[y]<r[x]) then writeln('1')
      else if (l[y]<l[x]) and (r[x]<r[y]) then writeln('2')
      else writeln('0');
   end;

   close(input);
   close(output);
end.

Tyvj Q1043(跳格游戏)

Problem C:
   简单DP  f[i][0]表示第偶数次到i,f[i][1]表示第奇数次到i
   f[i][0]=max(f[j][1])-a[i]  1<=j<i
   f[i][1]=max(f[j][0])+a[i]  1<=j<i

考虑不走这格的情况f[i][0]=f[i-1][0]  假设能这么走,显然不影响答案而少枚一维

由于偶数扣分 所以最后走的一定是单步

答案为f[n][1]

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<cmath>
#include<functional>
#include<algorithm>
using namespace std;
#define MAXN (30000+10)
int n,a[MAXN],f[MAXN][2]={0};
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		f[i][1]=a[i];
	}
	for (int i=1;i<=n;i++)
	{
		f[i][1]=max(max(f[i][1],f[i-1][1]),f[i-1][0]+a[i] );

		f[i][0]=max(max(f[i][0],f[i-1][0]),f[i-1][1]-a[i]);
	}
/*	for (int i=1;i<=n;i++) cout<<f[i][1]<<' ';
	cout<<endl;
	for (int i=1;i<=n;i++) cout<<f[i][0]<<' ';
	cout<<endl;

*/
/*
	int ans=f[1][1];
	for (int i=2;i<=n;i++) ans=max(ans,max(f[i][1],f[i][0]));
	cout<<ans<<endl;
*/
	cout<<f[n][1]<<endl;

	return 0;
}

Tyvj Q1027(多关键字排序)

多关键字排序

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<cmath>
#include<functional>
#include<algorithm>
using namespace std;
#define MAXN (500000)
int n;
struct score
{
	int no,a,b,c,d,e,f;
	friend bool operator<(const score a,const score b)
	{
		return (a.a!=b.a)?a.a>b.a:(a.b!=b.b)?a.b>b.b:(a.c!=b.c)?a.c>b.c:(a.d!=b.d)?a.d>b.d:(a.e!=b.e)?a.e>b.e:(a.f!=b.f)?a.f>b.f:a.no<b.no;
	}
}a[MAXN];
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		scanf("%d%d%d%d%d%d%d",&a[i].no,&a[i].a,&a[i].b,&a[i].c,&a[i].d,&a[i].e,&a[i].f);
	sort(a+1,a+1+n);
	for (int i=1;i<=n;i++)
		printf("%d %d %d %d %d %d %dn",a[i].no,a[i].a,a[i].b,a[i].c,a[i].d,a[i].e,a[i].f);
	return 0;
}

Tyvj P2058(Map)

c++ <map>的使用

其实由于x和y不相等,可以桶排的……

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<cmath>
#include<functional>
#include<algorithm>
#include<map>
using namespace std;
#define MAXN (1000+10)
#define MAXM (1000+10)
struct node
{
	int x,y,w;
	node():x(0),y(0),w(1){}
	node(int _x,int _y,int _w):x(_x),y(_y),w(_w){}

	friend bool operator<(const node a,const node b){ return (a.w!=b.w)?a.w<b.w:a.x+a.y>b.x+b.y;	}
	friend bool operator==(const node a,const node b){ return (a.x==b.x)&&(a.y==b.y);}
}a[MAXN];

int /*hash[MAXN+MAXM][2],*/n,m;
map<node,int> b;
int main()
{
	cin>>n>>m;
	for (int i=1;i<=n;i++)
	{
		scanf("%d%d",&a[i].x,&a[i].y);
		a[i].w=1;
		for (int j=1;j<i;j++)
		{
			if (a[i]==a[j]) a[i].w++;
		}
	}
	sort(a+1,a+1+n);
	for (int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		b[node(x,y,0)]=1;
	}
	for (int i=n;i>=1;i--)
	{
		if (b.find(node(a[i].x,a[i].y,0))==b.end() )
		{
			cout<<a[i].x<<' '<<a[i].y<<endl;
			return 0;


		}
	}




	return 0;
}

Tyvj P2059(传递闭包)

朴素的传递闭包

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<functional>
#include<algorithm>
#include<cctype>
using namespace std;
#define MAXN (100+10)
#define MAXM (4500+10)
bool f[MAXN][MAXN]={0};
int n,m;
int main()
{
	cin>>n>>m;
	for (int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		f[x][y]=1;
	}
	for (int k=1;k<=n;k++)
		for (int i=1;i<=n;i++)
			for (int j=1;j<=n;j++)
				f[i][j]=f[i][j]||f[i][k]&&f[k][j];
	int tot=0;
	for (int i=1;i<=n;i++)
	{
		for (int j=1;j<=n;j++)
			if (i!=j&&!(f[i][j]||f[j][i])) {tot--;break;}

		tot++;
	}
//	for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) cout<<f[i][j]<<' ';

	cout<<tot;
	return 0;
} 

ZOJ 2529(不同进制的高精度&sstream)

高精度 a+b

第i位的进制为第 ith 系数

慢慢做吧……

Important---:切记质数表一定要开大一些

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<iostream>
#include<functional>
#include<algorithm>
#include<sstream>
using namespace std;
int a[100],siz=0;
char a1[1000],a2[1000];
int A[1000],B[1000],C[1000];
void stod()
{

	istringstream ss(a1);
	int i=1;
	while (ss)
	{
		ss>>A[i];
		i++;
		char c;
		if (ss) ss>>c;
	}
	A[0]=i-1;
	stringstream ss2;
	ss2<<a2;
	i=1;
	while (ss2)
	{
		ss2>>B[i];
		i++;
		char c;
		if (ss2) ss2>>c;
	}
	B[0]=i-1;
	for (int i=1;i<=(A[0]>>1);i++) swap(A[i],A[A[0]-i+1]);
	for (int i=1;i<=(B[0]>>1);i++) swap(B[i],B[B[0]-i+1]);

}
int main()
{
	for (int i=1;siz<=80;i++)
	{
		bool flag=0;
		for (int j=2;j<=i-1;j++)
			if (i%j==0) flag=1;
		if (!flag)
		{
			siz++;
			a[siz]=i;
		}
	}
//	for (int i=1;i<=25;i++) cout<<a[i]<<' ';
	while (scanf("%s%s",a1,a2)!=EOF)
	{
		memset(A,0,sizeof(A));
		memset(B,0,sizeof(B));
		stod();
//		for (int i=1;i<=B[0];i++) cout<<B[i]<<' ';
		memset(C,0,sizeof(C));
		C[0]=max(A[0],B[0])+1;
		for (int i=1;i<=C[0];i++)
		{
			C[i]+=A[i]+B[i];
			C[i+1]+=C[i]/a[i+1];
			C[i]%=a[i+1];
		}
		while (!C[C[0]]) C[0]--;
		for (int i=C[0];i>=2;i--) cout<<C[i]<<",";
		cout<<C[1]<<endl;
	}
//	while (1);
	return 0;
}

ZOJ 2527(最长等差数列)

随便给一串数列,求最长等差数列

3方水过,回头附n^2logn算法 (dp[i][j][k]=dp[i][k]+1)

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<iostream>
#include<functional>
#include<algorithm>
using namespace std;
#define MAXN (10000+10)
int n,a[MAXN];
int main()
{
	while (scanf("%d",&n)!=EOF)
	{
		for (int i=1;i<=n;i++) scanf("%d",&a[i]);
		sort(a+1,a+1+n);
		int ans=2;
		for (int i=1;i<=n;i++)
			for (int j=i+1;j<=n;j++)
			{
				int dd=a[j]-a[i],now=j,tot=2;
				for (int k=j+1;k<=n;k++)
				{
					if (a[k]-a[now]==dd)
					{
						tot++;
						now=k;
					}
				}
				ans=max(ans,tot);

			}
		cout<<ans<<endl;

	}



	return 0;
}

ZOJ 1942(以路中最大边为价值的最短路)

Floyd 遍历

注意由于可能在第n步后,所以必须枚3方的

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<iostream>
#include<functional>
#include<algorithm>
using namespace std;
#define MAXN (2000+10)
#define MAXX (1000+10)
int n,x[MAXN],y[MAXN];
double dis(int i,int j)
{
	return sqrt(pow(abs(double(x[i]-x[j])),2)+pow(abs(double(y[i]-y[j])),2));
}
double d[MAXN][MAXN];
int main()
{
	int ii=1;
	while (1)
	{
		scanf("%d",&n);
		if (n==0) break;
		for (int i=1;i<=n;i++)
		{
			scanf("%d%d",&x[i],&y[i]);
		}



	//	for (int i=1;i<=n;i++) cout<<d[i]<<' ';
		for (int i=1;i<=n;i++)
		{
			for (int j=1;j<i;j++)
				d[i][j]=d[j][i]=dis(i,j);
		}
		for (int k=1;k<=n;k++)
			for (int i=1;i<=n;i++)
				for (int j=1;j<=n;j++)
					d[i][j]=min(d[i][j],max(d[i][k],d[k][j]));





		printf("Scenario #%dn",ii);
		printf("Frog Distance = %.3lfnn",d[1][2]);
//		cout<<d[1];



		ii++;
	}
	return 0;
}

草草草 (f(x)背包)

第三题  草草草(grass)

问题描述:

    有N棵小草,编号0至N-1。乐滋滋巨神不喜欢小草,所以乐滋滋要剪草,使得N棵小草的高度总和不超过H。在第0时刻,第i棵小草的高度是h[i],接下来的每个整数时刻,会依次发生如下三个步骤:

(1)每棵小草都长高了,第i棵小草长高的高度是grow[i]。

(2)乐滋滋选择其中一棵小草并把它剪平,这棵小草高度变为0。注意:这棵小草并没有死掉,它下一秒还会生长的。

(3)乐滋滋计算一下这N棵小草的高度总和,如果不超过H,则完成任务,一切结束,    否则轮到下一时刻。

你的任务是计算:最早是第几时刻,乐滋滋能完成他的任务?如果第0时刻就可以完成就输出0,如果永远不可能完成,输出-1,否则输出一个最早的完成时刻。

输入格式:

第一行,两个整数N和H。 1 ≤ N ≤ 50,0 ≤ H ≤ 1000000。

第二行,N个整数,表示h[i]。0 ≤ h[i] ≤ 100000。

第三行,N个整数,表示grow[i]。1 ≤ grow[i] ≤ 100000。

    对于20%的数据, 1 N
7。

输出格式:

  一个整数,最早完成时刻或-1。

输入输出样例:

输入样例

3  16

5  8  58

2  1  1 

2  58

5  8

2  1

 

2  0

5  8

2  1

 

7  33

5  1  6  5  8  4  7

2  1  1  1  4  3  2

输出样例

1

0

-1

5

样例解释

到了第1时刻,三棵小草的高度依次是7,9,59。如果乐滋滋把高度是59的小草剪掉,那么三棵小草高度是7+9+0=16,任务完成。

 

 

第1秒剪第2棵小草,第2秒剪第0棵小草,第3秒剪6棵小草,第4秒剪第5棵小草,第5秒剪第4棵小草。

 

本体是背包+贪心

由于值会变,需要对物品选取的先后顺序排序

毫无疑问   一棵草不可能✄两次 否则无解

另外,如果最后砍得草是已知的(对应题中N=最早时刻),那这题肯定是最后砍长得快的

进而衍生,倘若最后砍的草是确定的,先砍长得慢的

我们用w(i) 表示第i时刻的价值,显然不砍的话,它是单调递增的(grow[i]>0)

所以我们在砍长得第i慢的草时,只有长速为1~i-1 的草有可能被砍,后面的草一定不会砍的

所以它的状态可以由前(i-1)棵草 得到,有单调子结构,可以Dp背包

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<iostream>
#include<functional>
#include<algorithm>
using namespace std;
#define MAXH (1000000+10)
#define MAXN (50+10)
struct grass
{
	int h,g;
	friend bool operator<(const grass a,const grass b){return a.g<b.g;} //先割长得慢的,后割快的
    int w(const int i){return h+i*g;}
}a[MAXN];
int n,H,f[MAXN][MAXN];  //f[i][j]表示 到第i棵 且 取了 j 棵
bool is_ok(int m)
{
	memset(f,0,sizeof(f));

	for (int i=1;i<=n;i++)
		for (int j=1;j<=min(i,m);j++)
		{
			f[i][j]=max(f[i-1][j],f[i-1][j-1]+a[i].w(j));		//如果到第i次时割j稞最优值 就是0/1背包
		}
	int ans=0;
	for (int i=1;i<=n;i++) ans+=a[i].w(m);
	if (ans-f[n][m]<=H)
	{
		cout<<m<<endl;
//		while (1);
		exit(0);
	}


	return 0;
}
int main()
{
	freopen("grass.in","r",stdin);
	freopen("grass.out","w",stdout);
	scanf("%d%d",&n,&H);
	for (int i=1;i<=n;i++) cin>>a[i].h;
	for (int i=1;i<=n;i++) cin>>a[i].g;
	sort(a+1,a+1+n);
	for (int i=0;i<=n;i++) is_ok(i);
	cout<<"-1n";





//	while (1);
	return 0;
}