CF 286C(Main Sequence-贪心括号匹配)

C. Main Sequence
time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

As you know, Vova has recently become a new shaman in the city of Ultima Thule. So, he has received the shaman knowledge about the correct bracket sequences. The shamans of Ultima Thule have been using lots of different types of brackets since prehistoric times.
A bracket type is a positive integer. The shamans define a correct bracket sequence as follows:

  • An empty sequence is a correct bracket sequence.
  • If {a1, a2, ..., al} and {b1, b2, ..., bk} are
    correct bracket sequences, then sequence {a1, a2, ..., al, b1, b2, ..., bk} (their
    concatenation) also is a correct bracket sequence.
  • If {a1, a2, ..., al} —
    is a correct bracket sequence, then sequence  also is a correct bracket sequence, where v (v > 0) is
    an integer.

For example, sequences {1, 1,  - 1, 2,  - 2,  - 1} and {3,  - 3} are
correct bracket sequences, and {2,  - 3} is not.

Moreover, after Vova became a shaman, he learned the most important correct bracket sequence {x1, x2, ..., xn},
consisting of nintegers. As sequence x is the most
important, Vova decided to encrypt it just in case.

Encrypting consists of two sequences. The first sequence {p1, p2, ..., pn} contains
types of brackets, that is, pi = |xi| (1 ≤ i ≤ n).
The second sequence {q1, q2, ..., qt} contains t integers
这些地方必须取负数 {x1, x2, ..., xn}.

Unfortunately, Vova forgot the main sequence. But he was lucky enough to keep the encryption: sequences {p1, p2, ..., pn} and{q1, q2, ..., qt}.
Help Vova restore sequence x by the encryption. If there are multiple sequences that correspond to the encryption, restore any of them. If there are no
such sequences, you should tell so.

Input

The first line of the input contains integer n (1 ≤ n ≤ 106).
The second line contains n integers: p1, p2, ..., pn (1 ≤ pi ≤ 109).

The third line contains integer t (0 ≤ t ≤ n),
followed by t distinct integers q1, q2, ..., qt (1 ≤ qi ≤ n).

The numbers in each line are separated by spaces.

Output

Print a single string "NO" (without the quotes) if Vova is mistaken and a suitable sequence {x1, x2, ..., xn} doesn't
exist.

Otherwise, in the first line print "YES" (without the quotes) and in the second line print n integers x1, x2, ..., xn (|xi| = pixqj < 0).
If there are multiple sequences that correspond to the encrypting, you are allowed to print any of them.

Sample test(s)
input
2
1 1
0
output
YES
1 -1
input
4
1 1 1 1
1 3
output
YES
1 1 -1 -1
input
3
1 1 1
0
output
NO
input
4
1 2 2 1
2 3 4
output
YES
1 2 -2 -1

贪心,从后向前做,尽可能取左括号。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<functional>
#include<algorithm>
#include<stack>
using namespace std;
#define MAXN (1000000+10)
#define MAXP (1000000000+10)
int n,m,a[MAXN],ans[MAXN],tot;
bool b[MAXN];
int s[MAXN],size=0;
int main()
{
	memset(b,0,sizeof(b));
	scanf("%d",&n);tot=n+1;
	if (n%2) {printf("NOn");return 0;}
	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
	scanf("%d",&m);
	for (int i=1;i<=m;i++)
	{
		int p;
		scanf("%d",&p);
		b[p]=1;
	}
	for (int i=n;i;i--)
	{
		if (size==0||s[size]!=a[i]||b[i])
		{
			s[++size]=a[i];ans[--tot]=-a[i];
		}
		else ans[--tot]=s[size--];
	}
	if (size) printf("NOn");
	else
	{
		printf("YESn");
		for (int i=1;i<n;i++) printf("%d ",ans[i]);printf("%dn",ans[n]);
	}

	return 0;
}

圈地(斜率排序+坐标系旋转)

Problem 2 圈地(land.cpp/c/pas)

【题目描述】

2维平面上有n个木桩,你有一次圈地的机会并得到圈到的土地,为了体现你的高风亮节,你要使你圈到的土地面积尽量小。圈地需要圈一个至少3个点的多边形,多边形的顶点就是一个木桩,圈得的土地就是这个多边形内部的土地。

 

【输入格式】

第一行一个整数n,表示木桩个数。
  接下来n行,每行2个整数表示一个木桩的坐标,坐标两两不同。

【输出格式】

仅一行,表示最小圈得的土地面积,保留2位小数。

【样例输入】

样例1:
3

0 0

0 1

1 0

样例2:
4

0 0

0 1

0 2

1 1

【样例输出】

样例1:
0.50
样例2:
0.00
【数据范围】

    对于10%的数据,n<=100;
 对于30%的数据,n<=300;
 对于50%的数据,n<=500;
 对于100%的数据,n<=1000。

显然这题的多边形一定是三角形。

首先求出所有边,按k排序(必须先求出来,不能直接在排序的时候求)

然后考虑这些边,会发现正好是绕坐标系旋转一圈。

也就是说如果按照以这边为y轴从左至右排序,那么每转移一条边,只需要调换该边2个点的位置

这题没给范围,但是必须用long long

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
using namespace std;
#define MAXN (1000+10)
#define INF (1000000000)
#define eps 1e-10
struct P
{
	int x,y;
	long long operator*(const P &b)
	{
		return (long long)x*b.y-(long long)b.x*y;
	}
	friend bool operator<(P a,P b){if (a.x^b.x)	return a.x<b.x;return a.y<b.y;}
}a[MAXN];
long long abs2(long long x){if (x>0) return x;return -x;}
int n,h[MAXN];
struct E
{
	int i,j;
	double k;
	E(){}
	E(int _i,int _j):i(_i),j(_j){if (a[i].x==a[j].x) k=1e10;else k=(double)(a[i].y-a[j].y)/(a[i].x-a[j].x);}
	friend bool operator<(E a,E b){return a.k<b.k;	}
}e[MAXN*MAXN/2];
long long S2(P A,P B,P C)
{
	return abs2(A*B+B*C+C*A);
}
int size=0;
int main()
{
	freopen("land.in","r",stdin);
	freopen("land.out","w",stdout);
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
	long long ans=(long long)1<<60;
	/*
	for (int i=1;i<=n-2;i++)
		for (int j=i+1;j<n;j++)
			for (int k=j+1;k<=n;k++)
				ans=min(ans,abs2(a[i]*a[j]+a[j]*a[k]+a[k]*a[i]));
	*/

	sort(a+1,a+1+n);
	for (int i=1;i<=n;i++) h[i]=i;
	for (int i=1;i<n;i++)
		for (int j=i+1;j<=n;j++)
		{
			e[++size]=E(i,j);
		}

	sort(e+1,e+1+size);

	for (int i=1;i<=size&&ans;i++)
	{
		if (h[e[i].i]>1&&h[e[i].i]<n) ans=min(ans,S2(a[h[e[i].i]-1],a[h[e[i].i]],a[h[e[i].i]+1]));
		if (h[e[i].j]>1&&h[e[i].j]<n) ans=min(ans,S2(a[h[e[i].j]-1],a[h[e[i].j]],a[h[e[i].j]+1]));
		swap(a[h[e[i].i]],a[h[e[i].j]]);
		swap(h[e[i].i],h[e[i].j]);
	}

	printf("%.2lf",(double)ans/2);
	return 0;
}


CF 286B(Shifting-deque)

B. Shifting
time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

John Doe has found the beautiful permutation formula.

Let's take permutation p = p1, p2, ..., pn.
Let's define transformation f of this permutation:

 k (k > 1) 是每段长度, r 是最大满足 rk ≤ 的整数
 把 r
段和尾剩余部分(如果有)左移.

求序列 f(f( ... f(p = [1, 2, ..., n], 2) ... , n - 1), n) .

Input

一行 n (2 ≤ n ≤ 106).

Output

Print n distinct space-separated integers from 1 to n —
a beautiful permutation of size n.

Sample test(s)
input
2
output
2 1
input
3
output
1 3 2
input
4
output
4 2 3 1
Note

A note to the third test sample:

  • f([1, 2, 3, 4], 2) = [2, 1, 4, 3]
  • f([2, 1, 4, 3], 3) = [1, 4, 2, 3]
  • f([1, 4, 2, 3], 4) = [4, 2, 3, 1]
这题我是用WJMZBMR的神模拟过的。
先普及一下deque< >
deque<int> deq;   //建立双端队列
deq.push_back(x) 
deq.push_front(x) 
deq.pop_back(x) 
deq.pop_back(x) 
然后可以模拟了,每次把每段的最后搬上来。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
#define MAXN (1000000+10)
deque<int> deq;
int n;
int main()
{
	cin>>n;
	for (int i=1;i<=n;i++) deq.push_back(i);
	for (int i=2;i<=n;i++)
	{
		int l=(n-1)/i*i;deq.push_back(deq[l]);
		while (l-i>=0)
		{
			deq[l]=deq[l-i];
			l-=i;
		}
		deq.pop_front();
	}
	for (int i=0;i<deq.size();i++) cout<<deq[i]<<' ';
	return 0;
}

CF 286A(Lucky Permutation-数列找规律)

A. Lucky Permutation
time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

A permutation p of size n is the sequence p1, p2, ..., pn,
consisting of n distinct integers, each of them is from 1 to n (1 ≤ pi ≤ n).

A lucky permutation is such permutation p, that any integer i (1 ≤ i ≤ n) meets
this condition ppi = n - i + 1.

You have integer n. Find some lucky permutation p of
size n.

Input

The first line contains integer n (1 ≤ n ≤ 105)
— the required permutation size.

Output

Print "-1" (without the quotes) if the lucky permutation p of size n doesn't
exist.

Otherwise, print n distinct integers p1, p2, ..., pn (1 ≤ pi ≤ n) after
a space — the required permutation.

If there are multiple answers, you can print any of them.

Sample test(s)
input
1
output
1
input
2
output
-1
input
4
output
2 4 1 3
input
5
output
2 5 3 1 4 

找规律

如图所示



#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<iostream>
using namespace std;
int n;
int main()
{
	cin>>n;
	if (n%4>1)
	{
		cout<<"-1n";
		return 0;
	}
	for (int i=1;i<=n/2;i++)
	{
		if (i%2) cout<<i+1<<' ';
		else cout<<(n-i+2)<<' ';
	}
	int m=n/2;
	if (n%4==1)
	{
		cout<<m+1;
		if (m+1<n) cout<<' ';
		m++;
	}
	for (int i=m+1;i<n;i++)
	{
		if ((i-m)%2) cout<<n-i<<' ';
		else cout<<i-1<<' ';
	}
	if (m+1<n) cout<<(n-1);
	cout<<endl;
	return 0;
}

CF 287B(Pipeline-二分)

B. Pipeline
time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

Vova, the Ultimate Thule new shaman, wants to build a pipeline. As there are exactly n houses in Ultimate Thule, Vova wants the city to have exactly n pipes,
each such pipe should be connected to the water supply. A pipe can be connected to the water supply if there's water flowing out of it. Initially Vova has only one pipe with flowing water. Besides, Vova has several splitters.

A splitter is a construction that consists of one input (it can be connected to a water pipe) and x output pipes. When a splitter is connected to a water
pipe, water flows from each output pipe. You can assume that the output pipes are ordinary pipes. For example, you can connect water supply to such pipe if there's water flowing out from it. At most one splitter can be connected to any water pipe.


The figure shows a 4-output splitter

Vova has one splitter of each kind: with 234,
..., k outputs. Help Vova use the minimum number of splitters to build the required pipeline or otherwise state that it's impossible.

Vova needs the pipeline to have exactly n pipes with flowing out water. Note that some of those pipes can be the output pipes of the splitters.

Input

The first line contains two space-separated integers n and k (1 ≤ n ≤ 10182 ≤ k ≤ 109).

Please, do not use the %lld specifier to read or write 64-bit integers in С++. It is preferred to use the cincout streams
or the %I64dspecifier.

Output

Print a single integer — the minimum number of splitters needed to build the pipeline. If it is impossible to build a pipeline with the given splitters, print -1.

Sample test(s)
input
4 3
output
2
input
5 5
output
1
input
8 4
output
-1

这题显然优先找大的

直到找不下去了,判断无解或者拿个与需要的分水器相等的(显然有)

因为一个k的分水器只能增加k-1条通道

所以列方程


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<iostream>
using namespace std;
#define MAXN (1000000000000000000)
#define MAXK (1000000000)
long long n,k;
long long bin_s(long long l,long long r)
{
	if (n==1) return 0;
	while (r-l>1)
	{
		long long  m=(l+r)/2;
		if ((m+k-1)*(k-m)>2*(n-1)) l=m;
		else r=m;
	}
	if ((l+k-1)*(k-l)>2*(n-1)) l=r;
	if ((l+k-1)*(k-l)<2*(n-1)) l--;

	if (l==0) return -1;
	return k-l;
}
int main()
{
	cin>>n>>k;
	cout<<bin_s(1,k-1)<<endl;


	return 0;
}

CF 287A(IQ Test-枚举3个字符相等的矩阵)

A. IQ Test
time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

In the city of Ultima Thule job applicants are often offered an IQ test.

The test is as follows: the person gets a piece of squared paper with a 4 × 4 square painted on it. Some of the square's cells are painted black and others are painted
white. Your task is to repaint at most one cell the other color so that the picture has a 2 × 2 square,
completely consisting of cells of the same color. If the initial picture already has such a square, the person should just say so and the test will be completed.

Your task is to write a program that determines whether it is possible to pass the test. You cannot pass the test if either repainting any cell or no action doesn't result in a 2 × 2 square,
consisting of cells of the same color.

Input

Four lines contain four characters each: the j-th character of the i-th
line equals "." if the cell in the i-th row and the j-th
column of the square is painted white, and "#", if the cell is black.

Output

Print "YES" (without the quotes), if the test can be passed and "NO"
(without the quotes) otherwise.

Sample test(s)
input
####
.#..
####
....
output
YES
input
####
....
####
....
output
NO
Note

In the first test sample it is enough to repaint the first cell in the second row. After such repainting the required 2 × 2 square is on the intersection of the 1-st
and 2-nd row with the 1-st and 2-nd
column.

枚举看是否有一个矩形有3个字符相等
一开始居然把4个判断打错了?《上午也是……

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
using namespace std;
#define MAXLen (4+10)
char a[MAXLen][MAXLen];
bool flag=0;
int main()
{
	for (int i=1;i<=4;i++) scanf("%s",a[i]+1);
	for (int i=1;i<4;i++)
		for (int j=1;j<4;j++)
		{
			if (a[i][j]==a[i][j+1]&&a[i][j]==a[i+1][j]) flag=1;
			if (a[i][j]==a[i][j+1]&&a[i][j]==a[i+1][j+1]) flag=1;
			if (a[i][j]==a[i+1][j]&&a[i][j]==a[i+1][j+1]) flag=1;
			if (a[i+1][j]==a[i][j+1]&&a[i+1][j]==a[i+1][j+1]) flag=1;

		}
	if (flag) printf("YESn");
	else printf("NOn");
	return 0;
}

银河之星(记忆化搜索+9点染色)

Problem 3 银河之星(galaxy.cpp/c/pas)

数据组数不超过10.

这题就是记忆化搜索

9点染色减少状态,map记忆化

b[i][j][k]表示棋子可否从k方向到(i,j)

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<map>
using namespace std;
#define MAXN (100+10)
#define MAXK (10+10)
#define MAXDIV (4)
int k,n,m,x2,y2,a[MAXDIV][MAXDIV],b[MAXDIV][MAXDIV][9];
int c[8][2]={{0,1},{0,2},{1,0},{2,0},{1,1},{2,2},{1,2},{2,1}};  //↑↓→←↗↙↘↖
map<long long,int> h;
bool is_ok()
{
	int ans=0;
	for (int i=0;i<3;i++)
		for (int j=0;j<3;j++)
			ans=(11*ans+a[i][j]);
	if (h.find(ans)!=h.end()) return 0;
	return h[ans]=1;
}
bool dfs(int x)
{
	/*
	for (int j=3;j;j--)
		{
			for (int i=1;i<=3;i++)
				cout<<a[i%3][j%3];
			cout<<endl;
		}
		cout<<endl;
	*/
	if (!is_ok()) return 0;
	if (x==1)
	{
		if (a[x2][y2]) return 1;
		else return 0;
	}
	for (int i=0;i<3;i++)
		for (int j=0;j<3;j++)
			if (a[i][j])
			{
				for (int l=0;l<8;l++)
					if (a[(i+c[l][0])%3][(j+c[l][1])%3]&&a[(i+2*c[l][0])%3][(j+2*c[l][1])%3]<b[(i+2*c[l][0])%3][(j+2*c[l][1])%3][l])
					{
						a[i][j]--;a[(i+c[l][0])%3][(j+c[l][1])%3]--;a[(i+2*c[l][0])%3][(j+2*c[l][1])%3]++;
						if (dfs(x-1)) return 1;
						a[i][j]++;a[(i+c[l][0])%3][(j+c[l][1])%3]++;a[(i+2*c[l][0])%3][(j+2*c[l][1])%3]--;

					}
			}
	return 0;
}
int main()
{
	freopen("galaxy.in","r",stdin);
	freopen("galaxy.out","w",stdout);
	while (scanf("%d%d%d%d%d",&k,&n,&m,&x2,&y2)!=EOF)
	{
		x2%=3;y2%=3;
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		for (int i=0;i<3;i++)
			for (int j=0;j<3;j++)
			{
				int h=((n/3)+(i>0)*(i<=n%3)),r=((m/3)+(j>0)*(j<=m%3));
				//b[i][j][8]=((n/3)+(i>0)*(i<=n%3))*((m/3)+(j>0)*(j<=m%3));
				b[i][j][8]=h*r;
				if (j!=0) b[i][j][0]=max(r-1,0)*h;else b[i][j][0]=r*h;
				if ((m+1)%3!=j) b[i][j][1]=max(r-1,0)*h;else b[i][j][1]=r*h;
				if (i!=0) b[i][j][2]=max(h-1,0)*r;else b[i][j][2]=r*h;
				if ((n+1)%3!=i) b[i][j][3]=max(h-1,0)*r;else b[i][j][3]=r*h;
				b[i][j][4]=max(r-(j!=0),0)*max(h-(i!=0),0);
				b[i][j][5]=max(r-((m+1)%3!=j),0)*max(h-((n+1)%3!=i),0);
				b[i][j][6]=max(r-((m+1)%3!=j),0)*max(h-(i!=0),0);
				b[i][j][7]=max(r-(j!=0),0)*max(h-((n+1)%3!=i),0);
			}

		for (int i=1;i<=k;i++)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			a[x%3][y%3]++;
		}
		/*
		for (int j=3;j;j--)
		{
			for (int i=1;i<=3;i++)
				cout<<a[i%3][j%3];
			cout<<endl;
		}
		cout<<endl;
		*/
		if (dfs(k)) cout<<"Yesn";
		else cout<<"Non";
		h.clear();
	}
	return 0;
}



BZOJ 1084([SCOI2005]最大子矩阵-长矩阵Dp)

1084: [SCOI2005]最大子矩阵

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 586  Solved: 275
[Submit][Status][Discuss]

Description

这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。注意:选出的k个子矩阵不能相互重叠。

Input

第一行为n,m,k(1≤n≤100,1≤m≤2,1≤k≤10),接下来n行描述矩阵每行中的每个元素的分值(每个元素的分值的绝对值不超过32767)。

Output

只有一行为k个子矩阵分值之和最大为多少。

Sample Input

3 2 2

1 -3

2 3

-2 3

Sample Output

9

由于m不超过2
可以暴力Dp
分为m=1和m=2种情况
m=1就不用说了,
F[i][j][k]表示第1行到i第二行到j所能取到的最小值

#include<cstdio>
#include<cstring>
#include<iostream>
#include<functional>
#include<algorithm>
#include<cstdlib>
using namespace std;
#define MAXN (100+10)
#define MAXM (2+1)
#define MAXK (10+1)
int f[MAXN][MAXK],F[MAXN][MAXN][MAXK],n,m,k;
int a[MAXN][MAXN],sum[MAXN][MAXN];
int main()
{
	scanf("%d%d%d",&n,&m,&k);
	sum[0][1]=sum[0][2]=0;
	for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) scanf("%d",&a[i][j]),sum[i][j]=sum[i-1][j]+a[i][j];
	if (m==1)
	{
		memset(f,0,sizeof(f));
		for (int i=1;i<=n;i++)
		{
			f[i][0]=0;
			for (int l=1;l<=k;l++)
			{
				f[i][l]=f[i-1][l];
				for (int j=0;j<i;j++)
				{
					f[i][l]=max(f[i][l],f[j][l-1]+sum[i][1]-sum[j][1]);
				}
			}
		}
		cout<<f[n][k]<<endl;
	}
	else
	{
		memset(F,0,sizeof(F));
		for (int i=1;i<=n;i++)
		{
			for (int j=1;j<=n;j++)
			{
				F[i][j][0]=0;
				for (int l=1;l<=k;l++)
				{
					F[i][j][l]=max(F[i-1][j][l],F[i][j-1][l]);
					for (int i2=0;i2<i;i2++) F[i][j][l]=max(F[i][j][l],F[i2][j][l-1]+sum[i][1]-sum[i2][1]);
					for (int j2=0;j2<j;j2++) F[i][j][l]=max(F[i][j][l],F[i][j2][l-1]+sum[j][2]-sum[j2][2]);
					if (i==j)
						for (int j2=0;j2<i;j2++)
						{
							F[i][i][l]=max(F[i][i][l],F[j2][j2][l-1]+sum[i][1]-sum[j2][1]+sum[j][2]-sum[j2][2]);
						}
				}
			}
		}

		cout<<F[n][n][k]<<endl;

	}


	return 0;
}

CF 23E(Tree-树-背包合并)

Problem 2 树(tree.cpp/c/pas)

【题目描述】

L发明了一种与树有关的游戏(友情提醒:树是一个没有环的连通图):他从树中删除任意数量(可以为0)的边,计算删除后所有连通块大小的乘积,L将得到这么多的分数。你的任务就是对于一颗给定的树,求出L能得到的最大分数。

【输入格式】

第一行一个整数n,表示树的节点个数。
  接下来n-1行,每行两个整数a[i],b[i](1<=a[i],b[i]<=n),表示a[i]与b[i]之间连边。
  保证输入的图是一棵树。

【输出格式】

输出一个整数,表示L能得到的最大分数。

 【样例输入】

样例1:
5
1 2
2 3
3 4
4 5
样例2:
8
1 2
1 3
2 4
2 5
3 6
3 7
6 8
样例3:
3
1 2
1 3

【样例输出】

样例1:
6
样例2:
18
样例3:
3

【数据范围】

    对于10%的数据,1<=n<=5;
  对于30%的数据,1<=n<=100;
  另有30%的数据,保证数据是一条链。
  对于100%的数据,1<=n<=700;

 

树上背包

f[i][j]表示i的父亲的连通块在子树i中有j个的最大的最大值。

于是这就是树形Dp+背包合并了、

背包合并2个先合并,再与第三个……

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cstdlib>
#include<cmath>
using namespace std;
#define MAXN (700+10)
#define ll long long
#define F (100000000)
int n,edge[MAXN*2],pre[MAXN],next[MAXN*2],size=0,son[MAXN];
struct bign
{
	ll a[40];
	bign(){memset(a,0,sizeof(a));a[0]=1;}
	bign(int x){memset(a,0,sizeof(a)); a[0]=1;a[1]=x;	}
	ll& operator[](const int i){return a[i];	}
	friend bign operator*(bign a,bign b)
	{
		bign c;
		for (int i=1;i<=a[0];i++)
			for (int j=1;j<=b[0];j++)
			{
				c[i+j-1]+=a[i]*b[j];
				if (c[i+j-1]>F)
				{
					c[i+j]+=c[i+j-1]/F;
					c[i+j-1]%=F;
				}
			}
		c[0]=min(a[0]+b[0],(long long)39);while (!c[c[0]]&&c[0]>1) c[0]--;
		return c;
	}
	friend bool operator>(bign a,bign b)
	{
		if (a[0]!=b[0]) return a[0]>b[0];
		for (int i=a[0],j=b[0];i>0;i--,j--) if (a[i]!=b[j]) return a[i]>b[j];
		return false;
	}
	void print()
	{
		printf("%I64d",a[a[0]]);
		for (int i=a[0]-1;i;i--)
		{
			printf("%.8I64d",a[i]);
		}
	}
}f[MAXN][MAXN];
bign max(bign a,bign b)
{
	if (a>b) return a;
	return b;
}
void addedge(int u,int v)
{
	edge[++size]=v;
	next[size]=pre[u];
	pre[u]=size;
}
void dfs(int x,int father)
{
	son[x]=1;//f[x][1]=1;
	f[x][1]=1;
	for (int p=pre[x];p;p=next[p])
	{
		int &v=edge[p];
		if (v!=father)
		{
			dfs(v,x);
			/*
			for (int i=son[x]+son[v];i>0;i--)
			{
				if (i<son[x]) f[x][i]=f[x][i]*son[v];
				for (int k=son[v];k>=0;k--)
					if (i-k-1>=0) f[x][i]=max(f[x][i],f[x][i-k-1]*f[v][k]);

			}
			son[x]+=son[v];
			bign maxv=son[v];
			for (int k=0;k<=son[v]-1;k++) maxv=max(maxv,f[v][k]*(k+1));
			f[x][0]=f[x][0]*maxv;
			*/
			for (int i=son[x];i;i--)
				for (int j=son[v];j>=0;j--)
					f[x][i+j]=max(f[x][i+j],f[x][i]*f[v][j]);
			son[x]+=son[v];
		}
	}
	f[x][0]=bign(son[x]);
	for (int i=1;i<=son[x];i++) f[x][0]=max(f[x][0],f[x][i]*bign(i));




	return;
}
int main()
{
//	freopen("tree.in","r",stdin);
//	freopen("tree.out","w",stdout);
	scanf("%d",&n);
	memset(pre,0,sizeof(pre));
	memset(next,0,sizeof(next));
	for (int i=1;i<n;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		addedge(u,v);addedge(v,u);
	}
	addedge(n+1,1);
	dfs(n+1,0);	//n+1 is ans
	/*
	for (int i=1;i<=n+1;i++)
	{
		for (int j=0;j<=son[i]-1;j++)
		{
			f[i][j].print();printf(" ");
		}
		printf("n");
	}
	*/
//	f[n+1][1]=bign(123456789)*bign(234567899);

	f[1][0].print();
	printf("n");

	return 0;
}

RQNOJ 698(矩形计数-圆内接矩形数)

查看题目 Show Problem

题目:矩形计数

问题编号:698

题目描述

给出圆周上的N个点,请你计算出以这些点中的任意四个为四个角,能构成多少个矩形。
点的坐标是这样描述的,给定一个数组v[1..N],假设圆心为(0,0),圆的周长C=∑v[1..N] ,第一个点坐标为(0,C/(2π))。从第一个点开始,顺时针沿圆周走v1个单位长度,此时坐标为第二个点的坐标,再走v2个单位长度,此时为第三个点的坐标,当走完v1,v2..vi个距离后,为第i+1个点的坐标(全过程都是沿圆周顺时针)。特别的,走完v1,v2..vn个距离后,就会回到第一个点。

对于100%的数据,有N<=20,V数组中的所有元素的值<=100。

输入格式

输入共N+1行。
第一行为正整数N。
接下来N行每行一个正整数。其中第i+1行表示的是v[i]。

输出格式

输出共1行,一个整数,表示能构成的矩形的个数。

样例输入

8
1
2
2
3
1
1
3
3

样例输出

3

//样例解释[img]http://www.rqnoj.cn/ProblemPic/P698-101656.png[/img]

观察图片,易发现圆内的内接矩形对角线交点必过圆心(初中证明……)

所以只要找到所有对角线就行了


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#include<cmath>
#include<cstdlib>
using namespace std;
#define MAXN (100+10)
int n,c=0,m=0,a[MAXN];
int main()
{
	scanf("%d",&n);
	a[1]=0;
	for (int i=2;i<=n;i++)
	{
		scanf("%d",&a[i]),c+=a[i];
		if (!a[i]) i--,n--;
		else a[i]=c;
	}
	int p;
	scanf("%d",&p);c+=p;
	int l=1,r=1;
	while (r<=n&&l<=n)
	{
		if (a[r]-a[l]==c/2) {/*cout<<l<<' '<<r<<endl;*/m++;l++;}
		else if (a[r]-a[l]<c/2) r++;
		else l++;
	}
	cout<<m*(m-1)/2<<endl;
	return 0;
}