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;
}

艾呀喵啊 (特判与大数)

题目描述:

艾星人和喵星人开战了!

但是CWY发现,这只是大宇宙意志的一场“阴谋”,旨在控制艾星和喵星的人口数量。

战争最后的结果无非就是两败俱伤,人口锐减。

但是CWY想知道是艾星和喵星的人口总数是多少,以此预知战争的伤亡情况。

艾星和喵星人口总数为n,分别标号1到n,其中艾星人的标号是1到n中属于给定的等差数列或等比数列的数字。

给定等差数列的首项a,公差b,等比数列的首项c,公比d,你的任务是求出艾星人的个数。

输入格式:

一行,5个整数,分别是a,b,c,d,n。

(1≤a,b,c,n≤1012,  1≤d≤105。)

对于80%的数据,1≤n≤1000000。

输出格式:

一个整数,表示艾星人个数。

输入输出样例:

输入样例

1  1  1  2  1000

3  3  1  2  1000

452  24  4  5  600

输出样例

1000

343

10

样例解释

产生的等差数列是:1,2,3,4,….

产生的等比数列是:1,2,4,8,….

所以【1,1000】范围内所有标号都是艾星人的。

 

艾星人的10个数分别是: 4,20,100,452,476,500,524,548,572,596

 

 

今天不知道为什么调试器暴走……

而且把a>n的特判给打反

这题就是先算出等比的,再算等差(指数函数很快,记得用int64) ,再特判

Program queue;
var
   a,b,c,d,n,ans,i,ii:int64;
function is_ok:boolean;
begin
   if (a>n) then exit(false);

   if (c-a>=0) then
      if ((c-a) mod b=0) then
         if ((c-a) div b>=-1) then exit(true);
   exit(false);

end;
begin
   assign(input,'queue.in');
   assign(output,'queue.out');
   reset(input);
   rewrite(output);


   read(a,b,c,d,n);
   if (a>n) then ans:=0
   else ans:=(n-a) div b+1;

   while (c<=n) do
   begin
      if (not(is_ok) ) then inc(ans);
      c:=c*d;
      if (d=1) then break;
   end;
   writeln(ans);

   close(input);
   close(output);

end.

后院 (组合数+线段判重)

题目描述】

    左下角是(0,0),右上角是(W,H)的网格上,有(W+1)*(H+1)个格点。现在要在格点上找N个不同的点,使得这些点在一条直线上。并且在这条直线上,相邻点之间的距离不小于D。求方案数模1,000,000,000。

【输入格式】

    第一行一个整数T,表示数据组数。

       接下来T行,每行四个整数N,W,H,D,意义如题目描述。

【输出格式】

    T行,每行一个整数表示答案。

【输入输出样例】

backyard.in

backyard.out

6

2 4 4 1

13 36 48 5

5 5 5 1

50 49 49 1

6 5 5 2

10 55 75 5

300

2

88

102

0

490260662

 

【数据规模】

    20%的数据,N,W,H,D≤10。

    50%的数据,W,H,D≤100。

    另20%的数据,N≤5。

    100%的数据,N≤50,W,H,D≤500,T≤20。

 

首先是C(n,k) 的求法

	C[0][0]=1;
	for (int i=1;i<=501;i++)
	{
		C[i][0]=C[i][i]=1;
		for (int j=1;j<=i-1;j++)
			C[i][j]=(C[i-1][j]+C[i-1][j-1])%F;
	}

这个要背……

其次是判重

每次枚举是不要枚举一条直线,而要枚举一条线段(前后端点必取的)

注意要把线段放入点中,有(n-1)*(k-1)条线段,这些线段是为了让每段都大于d的最小点数,注意最小间隔+1的精度为ceil(k=trunc(d/dis-1e-7)+1)

注意在这种有长度限制(>=d)的题中,先把要添的点填上,再算组合数)

这样就没重复了,枚举一条线段的数量 显然为 (w-i+1)*(h-j+1) 注意用Longlong

回到原题,发现这样是无法考虑N=1,即只有一个店的情况,故特判,显然为网格上的所有点(w+1)*(h+1)

还要考虑堆成的线段->但是横纵线是不需要*2的

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<functional>
#include<algorithm>
using namespace std;
#define MAXN (50+10)
#define MAXW (500+10)
#define MAXH (500+10)
#define MAXD (500+10)
#define MAXT (20+10)
#define F (1000000000)
#define eps 1e-10
int t,n,w,h,d;
long long C[MAXW][MAXH]={0};
int gcd(int a,int b)
{
	if (b==0) return a;
	else return gcd(b,a%b);
}
int main()
{
	freopen("backyard.in","r",stdin);
	freopen("backyard.out","w",stdout);
	scanf("%d",&t);

	C[0][0]=1;
	for (int i=1;i<=501;i++)
	{
		C[i][0]=C[i][i]=1;
		for (int j=1;j<=i-1;j++)
			C[i][j]=(C[i-1][j]+C[i-1][j-1])%F;
	}

	while (t)
	{
		long long ans=0;
		scanf("%d%d%d%d",&n,&w,&h,&d);


		// 枚举 totnode-2取 ? 时。至少有2个点才不会Re
		if (n==1)
		{
			cout<<(w+1)*(h+1)<<endl;
			t--;
			continue;
		}

		for (int i=0;i<=w;i++)
			for (int j=0;j<=h;j++)	//(0,0)->(x,y)
			{
				if (i==0&&j==0) continue;
				int g=gcd(i,j);
				int totnode=g+1;  //直线上整点数
				if (totnode<n) continue;
				double dis=sqrt(double((i/g)*(i/g)+(j/g)*(j/g)));
				int k=int(trunc(double(d)/dis-eps))+1; //最少的能拼凑>=d的dis段数	eg:d=2 dis=1 k=2	d=2.5 dis=1 k=3
				if (k*(n-1)+1>totnode) continue; //段数n*[...)  +右端点
				ans=(ans+(i==0||j==0?1:2 )*((((w-i+1)*(h-j+1))%F)*(C[totnode-2-(n-1)*(k-1)][n-2]%F)))%F;  //横线 纵线的特判
		//		cout<<ans;

		//		cout<<i<<' '<<j<<' '<<ans<<endl;
			}
		t--;
		printf("%dn",ans);
	}
//	while (1);
	return 0;
}