数位和乘积(高精组合数学)

Problem 3 数位和乘积(digit.cpp/c/pas)

【题目描述】

一个数字的数位和乘积为其各位数字的乘积。求所有的N位数中有多少个数的数位和乘积恰好为K。请注意,这里的N位数是可以有前导零的。比如01,02视为二位数,但是他们的数位和乘积都是0。

 

【输入格式】

一行两个整数N,K

 

【输出格式】

一个行一个整数表示结果。

 

【样例输入】

2 3

【样例输出】

2

【样例输入2】

2 0

【样例输出2】

19

 

【数据范围】

对于20%:N <= 6。

对于50%:N<=16

存在另外30%:K=0。

对于100%:N <= 50,0 <= K <= 10^9。

法1:

k=0时,ans=10^n-9^n

否则就用记忆化搜索填1..9的个数

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<cctype>
using namespace std;
#define MAXN (50+10)
#define F (10000)
int n,k;
struct highn
{
	int len,a[900];
	highn():len(1){memset(a,0,sizeof(a));}
	highn(int x)
	{
		memset(a,0,sizeof(a));
		int i=0;
		while (x)
		{
			a[++i]=x%F;
			x/=F;
		}
		len=i;
	}
	void print()
	{
		printf("%d",a[len]);
		for (int i=len-1;i;i--)
		{
	//		if (a[i]<10000) printf("0");
			if (a[i]<1000) printf("0");
			if (a[i]<100) printf("0");
			if (a[i]<10) printf("0");
			printf("%d",a[i]);
		}

	}
	friend highn operator+(highn& a,highn& b)
	{
		highn c;
		int maxlen=max(a.len,b.len);
		for (int i=1;i<=maxlen;i++)
		{
			c.a[i]=c.a[i]+a.a[i]+b.a[i];
			if (c.a[i]>F)
			{
				c.a[i+1]+=c.a[i]/F;
				c.a[i]%=F;
			}
		}
		c.len=maxlen+1;
		while (!c.a[c.len]&&c.len>1) c.len--;
		return c;

	}
	friend highn operator-(highn& a,highn& b)
	{
		highn c;
		int maxlen=a.len;
		for (int i=1;i<=maxlen;i++)
		{
			c.a[i]+=a.a[i]-b.a[i];
			if (c.a[i]<0)
			{
				c.a[i+1]--;
				c.a[i]+=F;
			}
		}
		c.len=maxlen;
		while (!c.a[c.len]&&c.len>1) c.len--;
		return c;
	}
	friend highn operator*(highn& a,highn& b)
	{
		highn c;
		for (int i=1;i<=a.len;i++)
		{
			for (int j=1;j<=b.len;j++)
			{
				c.a[i+j-1]+=a.a[i]*b.a[j];
				if (c.a[i+j-1]>F)
				{
					c.a[i+j]+=c.a[i+j-1]/F;
					c.a[i+j-1]%=F;
				}
			}
		}
		c.len=a.len+b.len+1;
		while (!c.a[c.len]&&c.len>1) c.len--;
		return c;
	}

};
highn pow2(highn a,int b)
{
	highn c;
	if (!b) return 1;
	if (b%2)
	{
		c=pow2(a,b/2);
		c=c*c;
		c=c*a;
	}
	else
	{
		c=pow2(a,b/2);
		c=c*c;
	}
	return c;
}
int a[11],tot,b[11];
highn ans,C[51][51];
void dfs(int deep,highn rel,int hasget)
{
	if (n<hasget) {return;}
	if (deep==0||n==hasget)
	{
		for (int i=1;i<=9;i++) if (b[i]) return;
		ans=ans+rel;
		return;
	}
	else if (deep==9)
	{
		int m=min(n-hasget,b[3]/2);
		for (int i=0;i<=m;i++)
		{
			b[3]-=i*2;
			dfs(8,rel*C[n-hasget][i],hasget+i);
			b[3]+=i*2;
		}
	}
	else if (deep==8)
	{
		int m=min(n-hasget,b[2]/3);
		for (int i=0;i<=m;i++)
		{
			b[2]-=i*3;
			dfs(6,rel*C[n-hasget][i],hasget+i);
			b[2]+=i*3;
		}
	}
	else if (deep==6)
	{
		int m=min(n-hasget,min(b[2],b[3]));
		for (int i=0;i<=m;i++)
		{
			b[2]-=i;b[3]-=i;
			dfs(4,rel*C[n-hasget][i],hasget+i);
			b[2]+=i,b[3]+=i;
		}
	}
	else if (deep==4)
	{
		int m=min(n-hasget,b[2]/2);
		for (int i=0;i<=m;i++)
		{
			b[2]-=i*2;
			dfs(2,rel*C[n-hasget][i],hasget+i);
			b[2]+=i*2;
		}
	}
	else
	{
		if (b[2]+b[3]+b[5]+b[7]+hasget<=n)
		{
			int f[4]={2,3,5,7};
			for (int i=0;i<4;i++)
			{
				rel=rel*C[n-hasget][b[f[i]]];
				hasget+=b[f[i]];
			}
			ans=ans+rel;
			return ;
		}
	}
}
int main()
{
//	highn a=1254321,b=7612345;
//	highn c=pow(a,3);
//	c.print();
	freopen("digit.in","r",stdin);
	freopen("digit.out","w",stdout);
	scanf("%d%d",&n,&k);
	if (!k)
	{
		highn c=pow2(10,n),d=pow2(9,n);
		highn e=c-d;
		e.print();
	}
	else
	{

		memset(a,0,sizeof(a));
		tot=0;
		C[0][0]=1;
		for (int i=1;i<=n;i++)
		{
			C[i][0]=C[i][1]=1;
			for (int j=1;j<=i;j++)
			{
				C[i][j]=C[i-1][j]+C[i-1][j-1];
			}
		}
//		C[16][10].print();

		for(int i=2;i<=9;i++)
		{
			while (k%i==0)
			{
				a[i]++;
				k/=i;
				tot++;
			}
		}
		memcpy(b,a,sizeof(a));
		if (k==1) dfs(9,1,0);
		ans.print();
	}
	cout<<endl;
	return 0;
}

法2:

f[i][j][k][l][m]表示填到第i个数,2,3,5,7分别用j,k,l,m个的方案数

考虑后面填1..9的情况(显然不可能填0)

Bug:n=50,C(n,m)最大为C(50,25),可用long long.

----

----

法3:

容易发现

k=2^a*3^b*5^c*7^d时才有解

而且5,7取了当且只当数位为5,7的情况.

2-2,4,6,8

3-3,6,9

5-5

7-7

故可只考虑2,3,不考虑5,7

f[i][j]k]表示i位,取了j个2和k个3后的方案数,

因为可以用1填充,

所以答案=∑f[p][j][k]*C(p,j+k)*C(n,a[5])*C(n-a[5],a[7]) (p<=n-a[5]-a[7])



BZOJ 1507(文字编辑器-块状链表)

1507: [NOI2003]Editor

Time Limit: 5 Sec  Memory Limit: 162 MB
Submit: 922  Solved: 323
[Submit][Status][Discuss]

Description

很久很久以前,DOS3.x 的程序员们开始对 EDLIN 感到厌倦。于是,人们开始纷纷改用自己写的文本编辑器……
多年之后,出于偶然的机会,小明找到了当时的一个编辑软件。进行了一些简单的测试后,小明惊奇地发现:那个软件每秒能够进行上万次编辑操作(当然,你不能手工进行这样的测试)!于是,小明废寝忘食地想做一个同样的东西出来。你能帮助他吗?
为了明确任务目标,小明对“文本编辑器”做了一个抽象的定义:
文本:由 0 个或多个字符构成的序列。这些字符的 ASCII 码在闭区间[32, 126]内,也就是说,这些字符均为可见字符或空格。
光标:在一段文本中用于指示位置的标记,可以位于文本的第一个字符之前,文本的最后一个字符之后或文本的某两个相邻字符之间。
文本编辑器:为一个可以对一段文本和该文本中的一个光标进行如下六条操作的程序。
如果这段文本为空,我们就说这个文本编辑器是空的。

你的任务是:
 建立一个空的文本编辑器。
 从输入文件中读入一些操作指令并执行。
 对所有执行过的 GET 操作,将指定的内容写入输出文件。

Input

第一行是指令条数 t,以下是需要执行的 t 个操作。其中:
为了使输入文件便于阅读,Insert 操作的字符串中可能会插入一些回车符,请忽略掉它们(如果难以理解这句话,可以参考样例)。
除了回车符之外,输入文件的所有字符的 ASCII 码都在闭区间[32, 126]内。且行尾没
有空格。
这里我们有如下假定:
1. MOVE 操作不超过 50000 个,INSERT 和 DELETE 操作的总个数不超过 4000,PREV 和 NEXT 操作的总个数不超过 200000。
2. 所有 INSERT 插入的字符数之和不超过 2M(1M=1024*1024),正确的输出文件长度不超过 3M 字节。
3. DELETE 操作和 GET 操作执行时光标后必然有足够的字符。MOVE、PREV、NEXT操作不会把光标移动到非法位置。
4. 输入文件没有错误。
对 C++选手的提示:经测试,对最大的测试数据使用 fstream 进行输入有可能会比使用 stdio 慢约 1 秒,因此建议在可以的情况下使用后者。

Output

输出每行依次对应输入文件中每条GET指令的输出。

Sample Input

15
Insert 26
abcdefghijklmnop
qrstuv wxy
Move 16
Delete 11
Move 5
Insert 1
^
Next
Insert 1
_
Next
Next
Insert 4
.\/.
Get 4
Prev
Insert 1
^
Move 0
Get 22

Sample Output

.\/.
abcde^_^f.\/.ghijklmno

这题我是用块状链表做的

块状链表的复杂度大约是O(√n)

一定要尽可能将块分成长度为√tot的,balance()时要把所有的长度分为介于1/2√tot-2√tot之间

另外merge时要注意先把cur移动再重载合并格的长度(不容易查出错,不知为何,加错也能过8个点)

要参考老董的讲解nocow的模板

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define MAXP (1024*1024)
#define MAXN (2900)
struct block
{
int n;
char a[MAXN];
block *next,*pre;
block():n(0){next=pre=NULL;}
}*first;
block* q[MAXN];
int size=0,tot=0;
void del(block *x)
{
q[++size]=x;
if (x->pre) x->pre->next=x->next;
if (x->next) x->next->pre=x->pre;
if (x==first) first=x->next;
}
block *newblock()
{
if (size) return q[size--];
block *x=new block();
return x;
}
void link(block *a,block *b)
{
if (a) a->next=b;
if (b) b->pre=a;
}
void spilt(block *x,int nowsize)
{
if (!nowsize||nowsize==x->n) return;
block *tmp=x->next;
x->next=newblock();
block *x2=x->next;
x2->n=x->n-nowsize;
for (int i=1;i< =x2->n;i++) x2->a[i]=x->a[nowsize+i];
x->n=nowsize;
link(x2,tmp);
link(x,x2);
}
struct cursor
{
int n;
block *ll;
cursor():n(0){ll=first; }
void pre()
{
n--;
if (n<0)
{
ll=ll->pre;
n=ll->n-1;
}
}
void next()
{
n++;
if (n>ll->n)
{
ll=ll->next;
n=1;
}
}
void move(int k)
{
n=k,ll=first;
while (n>ll->n)
{
n-=ll->n;
ll=ll->next;
}
}
}cur;
void get(cursor cur,int k)
{
int p=cur.ll->n-cur.n;
if (p>=k)
{
for (int i=cur.n+1;i< =cur.n+k;i++) printf("%c",cur.ll->a[i]);
}
else
{
for (int i=cur.n+1;i< =cur.ll->n;i++) printf("%c",cur.ll->a[i]);
cur.ll=cur.ll->next;cur.n=0;
get(cur,k-p);
}
}
void merge(block *x)
{
if (!x->next) return;
for (int i=1;i< =x->next->n;i++) x->a[x->n+i]=x->next->a[i];
if (cur.ll==x->next)
{
cur.ll=x;
cur.n+=x->n;
}
x->n+=x->next->n;
del(x->next);
}
void balance()
{
int maxsize=min(MAXN,(int)sqrt(tot)*2);
int minsize=(int)sqrt(tot)/2;
block *x=first;
while (x)
{
while (x->nn>maxsize)
{
if (x->n
next) break;
// get(cur,1);
}
else
{
spilt(x,(x->n)>>1);
if (cur.ll==x&&cur.n>cur.ll->n)
{
cur.n-=cur.ll->n;
cur.ll=cur.ll->next;
}
// get(cur,1);
}
}
x=x->next;
}
}
void delet(int k)
{
if (!k) return;
if (cur.n)
{
spilt(cur.ll,cur.n);
cur.ll=cur.ll->next; cur.n=0;
}
while (k>cur.ll->n)
{
del(cur.ll);
k-=cur.ll->n;
cur.ll=cur.ll->next;
// cur.n=0;
}
if (k==cur.ll->n)
{
cur.ll->n=0;
}
else
{
spilt (cur.ll,k);
delet(k);
}
balance();
}
void insert(int k)
{
block *l=newblock();*l=block();
block *r=l;
int maxsize=min(MAXN,(int)sqrt(tot));
for (int i=1;i< =k;i++) { char c; for (scanf("%c",&c);(c<32)||(c>126)||(c=='\n');scanf("%c",&c));
if (r->n>maxsize)
{
block *tmp=r;
r=newblock();*r=block();link(tmp,r);
}
r->a[++r->n]=c;
}
if (cur.n)
{
spilt(cur.ll,cur.n);
block *tmp=cur.ll->next;
link(cur.ll,l),link(r,tmp);
}
else
{
link(cur.ll->pre,l),link(r,cur.ll),cur.ll=l;
if (first->pre) first=l;
}
balance();
}
int main()
{
first=newblock();cur.ll=first;
int t;scanf("%d",&t);
while (t--)
{
char s[10];
scanf("%s",s);
int k;
switch(s[0])
{
case'M':scanf("%d",&k);cur.move(k);break;
case'I':scanf("%d",&k);tot+=k;insert(k);break;
case'D':scanf("%d",&k);tot-=k;delet(k);break;
case'G':scanf("%d",&k);get(cur,k);printf("\n");break;
case'P':cur.pre();break;
case'N':cur.next();break;
}
// get(cursor(),tot);cout<

 

BZOJ 1507([NOI2003]Editor-块状链表)

1507: [NOI2003]Editor

Time Limit: 5 Sec  Memory Limit: 162 MB
Submit: 922  Solved: 323
[Submit][Status][Discuss]

Description

很久很久以前,DOS3.x 的程序员们开始对 EDLIN 感到厌倦。于是,人们开始纷纷改用自己写的文本编辑器……
多年之后,出于偶然的机会,小明找到了当时的一个编辑软件。进行了一些简单的测试后,小明惊奇地发现:那个软件每秒能够进行上万次编辑操作(当然,你不能手工进行这样的测试)!于是,小明废寝忘食地想做一个同样的东西出来。你能帮助他吗?
为了明确任务目标,小明对“文本编辑器”做了一个抽象的定义:
文本:由 0 个或多个字符构成的序列。这些字符的 ASCII 码在闭区间[32, 126]内,也就是说,这些字符均为可见字符或空格。
光标:在一段文本中用于指示位置的标记,可以位于文本的第一个字符之前,文本的最后一个字符之后或文本的某两个相邻字符之间。
文本编辑器:为一个可以对一段文本和该文本中的一个光标进行如下六条操作的程序。
如果这段文本为空,我们就说这个文本编辑器是空的。

你的任务是:
 建立一个空的文本编辑器。
 从输入文件中读入一些操作指令并执行。
 对所有执行过的 GET 操作,将指定的内容写入输出文件。

Input

第一行是指令条数 t,以下是需要执行的 t 个操作。其中:
为了使输入文件便于阅读,Insert 操作的字符串中可能会插入一些回车符,请忽略掉它们(如果难以理解这句话,可以参考样例)。
除了回车符之外,输入文件的所有字符的 ASCII 码都在闭区间[32, 126]内。且行尾没
有空格。
这里我们有如下假定:
1. MOVE 操作不超过 50000 个,INSERT 和 DELETE 操作的总个数不超过 4000,PREV 和 NEXT 操作的总个数不超过 200000。
2. 所有 INSERT 插入的字符数之和不超过 2M(1M=1024*1024),正确的输出文件长度不超过 3M 字节。
3. DELETE 操作和 GET 操作执行时光标后必然有足够的字符。MOVE、PREV、NEXT操作不会把光标移动到非法位置。
4. 输入文件没有错误。
对 C++选手的提示:经测试,对最大的测试数据使用 fstream 进行输入有可能会比使用 stdio 慢约 1 秒,因此建议在可以的情况下使用后者。

Output

输出每行依次对应输入文件中每条GET指令的输出。

Sample Input

15

Insert 26

abcdefghijklmnop

qrstuv wxy

Move 16

Delete 11

Move 5

Insert 1

^

Next

Insert 1

_

Next

Next

Insert 4

./.

Get 4

Prev

Insert 1

^

Move 0

Get 22

Sample Output

./.

abcde^_^f./.ghijklmno

这题我是用块状链表做的

块状链表的复杂度大约是O(√n)

一定要尽可能将块分成长度为√tot的,balance()时要把所有的长度分为介于1/2√tot-2√tot之间

另外merge时要注意先把cur移动再重载合并格的长度(不容易查出错,不知为何,加错也能过8个点)

要参考老董的讲解nocow的模板

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cmath>
using namespace std;
#define MAXP (1024*1024)
#define MAXN (2900)
struct block
{
    int n;
    char a[MAXN];
    block *next,*pre;
    block():n(0){next=pre=NULL;}
}*first;
block* q[MAXN];
int size=0,tot=0;
void del(block *x)
{
    q[++size]=x;
    if (x->pre) x->pre->next=x->next;
    if (x->next) x->next->pre=x->pre;
    if (x==first) first=x->next;
}
block *newblock()
{
    if (size) return q[size--];
    block *x=new block();
    return x;
}
void link(block *a,block *b)
{
    if (a) a->next=b;
    if (b) b->pre=a;
}
void spilt(block *x,int nowsize)
{
    if (!nowsize||nowsize==x->n) return;
    block *tmp=x->next;
    x->next=newblock();
    block *x2=x->next;
    x2->n=x->n-nowsize;
    for (int i=1;i<=x2->n;i++) x2->a[i]=x->a[nowsize+i];
    x->n=nowsize;
    link(x2,tmp);
    link(x,x2);
}
struct cursor
{
    int n;
    block *ll;
    cursor():n(0){ll=first; }
    void pre()
    {
        n--;
        if (n<0)
        {
            ll=ll->pre;
            n=ll->n-1;
        }
    }
    void next()
    {
        n++;
        if (n>ll->n)
        {
            ll=ll->next;
            n=1;
        }
    }
    void move(int k)
    {
        n=k,ll=first;
        while (n>ll->n)
        {
            n-=ll->n;
            ll=ll->next;
        }
    }
}cur;
void get(cursor cur,int k)
{
    int p=cur.ll->n-cur.n;
    if (p>=k)
    {
        for (int i=cur.n+1;i<=cur.n+k;i++)
            printf("%c",cur.ll->a[i]);
    }
    else
    {
        for (int i=cur.n+1;i<=cur.ll->n;i++) printf("%c",cur.ll->a[i]);
        cur.ll=cur.ll->next;cur.n=0;
        get(cur,k-p);
    }
}
void merge(block *x)
{
    if (!x->next) return;
    for (int i=1;i<=x->next->n;i++) x->a[x->n+i]=x->next->a[i];
    if (cur.ll==x->next)
    {
        cur.ll=x;
        cur.n+=x->n;
    }
    x->n+=x->next->n;
    del(x->next);
}
void balance()
{
    int maxsize=min(MAXN,(int)sqrt(tot)*2);
    int minsize=(int)sqrt(tot)/2;
    block *x=first;
    while (x)
    {
        while (x->n<minsize||x->n>maxsize)
        {
            if (x->n<minsize)
            {
                merge(x);
                if (!x->next) break;
            //  get(cur,1);
            }
            else
            {
                spilt(x,(x->n)>>1);
                if (cur.ll==x&&cur.n>cur.ll->n)
                {
                    cur.n-=cur.ll->n;
                    cur.ll=cur.ll->next;
                }
            //  get(cur,1);
            }
        }
        x=x->next;
    }
}
void delet(int k)
{
    if (!k) return;
    if (cur.n)
    {
        spilt(cur.ll,cur.n);
        cur.ll=cur.ll->next; cur.n=0;
    }
    while (k>cur.ll->n)
    {
        del(cur.ll);
        k-=cur.ll->n;
        cur.ll=cur.ll->next;
    //  cur.n=0;
    }
    if (k==cur.ll->n)
    {
        cur.ll->n=0;
    }
    else
    {
        spilt (cur.ll,k);
        delet(k);
    }
    balance();
}
void insert(int k)
{
    block *l=newblock();*l=block();
    block *r=l;
    int maxsize=min(MAXN,(int)sqrt(tot));
    for (int i=1;i<=k;i++)
    {
        char c;
        for (scanf("%c",&c);(c<32)||(c>126)||(c=='n');scanf("%c",&c));
        if (r->n>maxsize)
        {
            block *tmp=r;
            r=newblock();*r=block();link(tmp,r);
        }
        r->a[++r->n]=c;
    }
    if (cur.n)
    {
        spilt(cur.ll,cur.n);
        block *tmp=cur.ll->next;
        link(cur.ll,l),link(r,tmp);
    }
    else
    {
        link(cur.ll->pre,l),link(r,cur.ll),cur.ll=l;
        if (first->pre) first=l;
    }
    balance();
}
int main()
{
    first=newblock();cur.ll=first;
    int t;scanf("%d",&t);
    while (t--)
    {
        char s[10];
        scanf("%s",s);
        int k;
        switch(s[0])
        {
            case'M':scanf("%d",&k);cur.move(k);break;
            case'I':scanf("%d",&k);tot+=k;insert(k);break;
            case'D':scanf("%d",&k);tot-=k;delet(k);break;
            case'G':scanf("%d",&k);get(cur,k);printf("n");break;
            case'P':cur.pre();break;
            case'N':cur.next();break;
        }
//      get(cursor(),tot);cout<<endl;
    }
    return 0;
}

OI Style

via 百度noip吧

哥尼斯堡七桥边我们的连线
丽洁神犇嫩模间难存的情缘
当图灵机看见这也会被停机
NP解释不了的难题
搜索会爆无向图慢慢去遍历
只为能够找到你心底的记忆
神器SPFA
队列进出我们的足迹
线性规划难找我们的交集
算心底的梦忆靠容斥原理
二进制连篇幅代我说真爱你
Dev-C感动得去编译
平衡树轻旋转你我在隔壁
将你我连一起矩阵快速幂
看你我完美结合算法多美丽
你眼带笑意
数字三角行阵间递推难了解
斐波那契数列中恩怨何时结
二叉树上的禁果摘下归你我
藏进最长非降序列里
01背包装不下曾经的点滴
一切伤痕作浮云压进栈之底
红娘一般的匈牙利
联系我们不用并查集
心如凸包体积计算不容易
增广路来拓宽一定走进你
用剪枝剪去一切别人的记忆
得与失并不用去博弈
大脑里我找你匹配KMP
仿佛昨日重现AC自动机
二分图你我牵手一起的奇迹
感动着天地

OIer&ACMER的十最 – Dr.Lib – Dr.Librazy

最有成就感的时刻:AC了一道POJAC率低于10%的题目
题目错了却最踏实的时刻:PE
最棘手的时刻:TLE
最粗心的时刻:CE
最无奈的时候:递归RE
最郁闷的时候:无数次修改后submit依然WA
最无语的时刻:调试数据也被输出结果OLE
最贪婪的时刻:空间换取时间…TLE
最夸张的时刻:惊现SE
最被BS的时刻:提交恶意代码…服务器死掉….
最幸福的时刻:AK

UVA 10209(Is This Integration ?-容斥原理)

Problem C
Is This Integration ?
Input: Standard Input
Output: Standard Output
Time Limit: 3 seconds

 

In the image below you can see a square ABCD, where AB = BC = CD = DA = a. Four arcs are drawn taking the four vertexes A, B, C, Das centers and a as the radius. The arc that is drawn taking A as
center, starts at neighboring vertex B and ends at neighboring vertex D. All other arcs are drawn in a similar fashion. Regions of three different shapes are created in this fashion. You will have to determine the total area
if these different shaped regions.  

 

Input

The input file contains a floating-point number a (a>=0 a<=10000) in each line which indicates the length of one side of the square. Input is terminated by end of file.  

 

Output

For each line of input, output in a single line the total area of the three types of region (filled with different patterns in the image above). These three numbers will of course be floating point numbers with three digits after the decimal point. First
number will denote the area of the striped region, the second number will denote the total area of the dotted regions and the third number will denote the area of the rest of the regions.

 

Sample Input:

0.1
0.2
0.3

Sample Output:

0.003 0.005 0.002
0.013 0.020 0.007
0.028 0.046 0.016


Shahriar Manzoor

设中间那块面积为x,四个角的面积为y,四个凹形的面积为z


则有

x+4y+4z=a^2

x+3y+2z=pi/4*a^2

x+2y+z=(pi/3-√3/4)a^2 (2个扇形-中间重叠的三角形)

解出:

x=(1+pi/3-√3)*a^2

y=(pi/12+√3/2-1)*a^2

z=(-pi/6+1-√3/4)*a^2

另:注意pi的精度

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
using namespace std;
#define MAXa (10000)
double a;
const double pi=3.141592653589793;
int main()
{
	while (scanf("%lf",&a)!=EOF)
	{
		printf("%.3lf %.3lf %.3lfn",a*a*(1+pi/3-sqrt(3.0)),a*a*(pi/3+2*sqrt(3.0)-4),a*a*(-2*pi/3+4-sqrt(3.0)));
	}
	return 0;
}


BZOJ 1500([NOI2005]维修数列-Splay的数列维护)

1500: [NOI2005]维修数列

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 3087  Solved: 920
[Submit][Status][Discuss]

Description

Input

输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目。 第2行包含N个数字,描述初始时的数列。 以下M行,每行一条命令,格式参见问题描述中的表格。

Output

对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。

Sample Input

9 8

2 -6 3 5 1 -5 -3 6 3

GET-SUM 5 4

MAX-SUM

INSERT 8 3 -5 7 2

DELETE 12 1

MAKE-SAME 3 3 2

REVERSE 3 6

GET-SUM 5 4

MAX-SUM

Sample Output

-1

10

1

10

HINT

Splay解决数列维护。

推荐:用伸展树解决数列维护问题

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cstdlib>
#include<cmath>
using namespace std;
#define MAXN (500000+10)
#define MAXM (20000+10)
#define INF (0xfffffff)
struct node
{
	int value,MaxL,MaxR,MaxM,sum,size;
	bool rev,same;
	node *ch[2],*pre;
	node(node *f,int _value,int _MaxL,int _MaxR,int _MaxM,int _sum,int _size):value(_value),MaxL(_MaxL),MaxR(_MaxR),MaxM(_MaxM),sum(_sum),size(_size){rev=same=0,pre=f,ch[0]=ch[1]=NULL;}
	node(){rev=same=0;}
	int l_siz(){if (ch[0]) return ch[0]->size;else return 0;}
//	int r_siz(){return (ch[1])?ch[1]->size:0;}

	friend void pushdown(node *x)
	{
		if (x)
		{
			if (x->rev)
			{
				x->rev=0;
				if (x->ch[0]) x->ch[0]->rev^=1;
				if (x->ch[1]) x->ch[1]->rev^=1;
				swap(x->ch[0],x->ch[1]);
				swap(x->MaxL,x->MaxR);
			}
			if (x->same)
			{
				x->same=0;
				if (x->ch[0]) {x->ch[0]->same=1;x->ch[0]->value=x->value;x->ch[0]->sum=x->value*x->ch[0]->size;x->ch[0]->MaxL=x->ch[0]->MaxR=x->ch[0]->MaxM=max(x->value,x->ch[0]->sum);}
				if (x->ch[1]) {x->ch[1]->same=1;x->ch[1]->value=x->value;x->ch[1]->sum=x->value*x->ch[1]->size;x->ch[1]->MaxL=x->ch[1]->MaxR=x->ch[1]->MaxM=max(x->value,x->ch[1]->sum);}
			}
		}
	}
	friend void update(node *x)
	{
		if (x)
		{
			pushdown(x->ch[0]);pushdown(x->ch[1]); //由于有坑爹的rev操作,必须先down.
			x->size=((x->ch[0])?x->ch[0]->size:0)+((x->ch[1])?x->ch[1]->size:0)+1;
			x->sum=((x->ch[0])?x->ch[0]->sum:0)+((x->ch[1])?x->ch[1]->sum:0)+x->value;
			x->MaxL=max(((x->ch[0])?x->ch[0]->MaxL:x->value),((x->ch[0])?x->ch[0]->sum:0)+x->value+max(0,((x->ch[1])?x->ch[1]->MaxL:0)));
			x->MaxR=max(((x->ch[1])?x->ch[1]->MaxR:x->value),((x->ch[1])?x->ch[1]->sum:0)+x->value+max(0,((x->ch[0])?x->ch[0]->MaxR:0)));
		//	cout<<((x->ch[1])?x->ch[1]->MaxR:x->value)<<' '<<+max(0,(((x->ch[0])?x->ch[0]->MaxR:0)))<<endl;
			x->MaxM=max(max(((x->ch[0])?x->ch[0]->MaxM:x->value),((x->ch[1])?x->ch[1]->MaxM:x->value)),((x->ch[0])?max(x->ch[0]->MaxR,0):0)+((x->ch[1])?max(x->ch[1]->MaxL,0):0)+x->value);
		}
	}
};
node *q[MAXN];
int q_siz=0;
int n,m,a[MAXN];
node* newnode(node *f,int value,int MaxL,int MaxR,int MaxM,int sum,int size)
{
	if (q_siz)
	{
		q[q_siz]->value=value;
		q[q_siz]->MaxL=MaxL;
		q[q_siz]->MaxR=MaxR;
		q[q_siz]->MaxM=MaxM;
		q[q_siz]->sum=sum;
		q[q_siz]->size=size;
		q[q_siz]->rev=q[q_siz]->same=0;q[q_siz]->pre=f;q[q_siz]->ch[0]=q[q_siz]->ch[1]=NULL;
		return q[q_siz--];
	}
	node *x=new node(f,value,MaxL,MaxR,MaxM,sum,size);
	return x;
}
node* newnode()
{
	if (q_siz) return q[q_siz--];
	node *x=new node();
	return x;
}
void addnode(node *x)
{
	q[++q_siz]=x;
	*x=node();
}
struct Splay
{
	node *root;
	Splay()
	{
		root=newnode(NULL,-INF,-INF,-INF,-INF,0,2);
		root->ch[0]=newnode(root,-INF,-INF,-INF,-INF,0,1);
	}
	void Print(node *x)
	{
		if (x->ch[0]) {cout<<"(",Print(x->ch[0]),cout<<")-";}
		cout<<x->same;
		if (x->ch[1]) cout<<"-(",Print(x->ch[1]),cout<<")";
	}
	void rotate(node *x,int c) //0左旋 1右旋
	{
		node *y=x->pre;
		pushdown(y),pushdown(x);
		y->ch[!c]=x->ch[c];
		if (x->ch[c]!=NULL) x->ch[c]->pre=y;
		x->pre=y->pre;
		if (y->pre!=NULL)
		{
			if (y->pre->ch[0]==y) y->pre->ch[0]=x;
			else y->pre->ch[1]=x;
		}
		x->ch[c]=y;y->pre=x;
		if (y==root) root=x;
		update(y);
	}
	void splay(node *x,node *f)
	{
		for(pushdown(x);x->pre!=f;)
		{
			if (x->pre->pre==f)
			{
				if (x->pre->ch[0]==x) rotate(x,1);
				else rotate(x,0);
			}
			else
			{
				node *y=x->pre,*z=y->pre;
				pushdown(z);pushdown(y);pushdown(x); //rev改变树结构
				if (y->ch[0]==x&&z->ch[0]==y) rotate(y,1),rotate(x,1);
				else if (y->ch[1]==x&&z->ch[1]==y) rotate(y,0),rotate(x,0);
				else if (y->ch[0]==x&&z->ch[1]==y) rotate(x,1),rotate(x,0);
				else if (y->ch[1]==x&&z->ch[0]==y) rotate(x,0),rotate(x,1);
			}
			update(x);
			//Print(root);cout<<endl;
		}
	}
	node* find_kth(node *x,int k)
	{
		pushdown(x); //确保x正确
		if (x->l_siz()>=k) return find_kth(x->ch[0],k);
		if (x->l_siz()+1==k) return x;
		else return find_kth(x->ch[1],k-x->l_siz()-1);
	}
	void build(node *f,node *x,int l,int r)
	{
		if (l>r) return;
		int m=(l+r)>>1;
		*x=node(f,a[m],a[l],a[r],a[m],a[m],1);
		if (l<m) build(x,x->ch[0]=newnode(),l,m-1);
		if (m<r) build(x,x->ch[1]=newnode(),m+1,r);
		if (l<r) update(x);
	}
	void del(node *x)
	{
		if (x->ch[0]) del(x->ch[0]);
		if (x->ch[1]) del(x->ch[1]);
		addnode(x);
	}
	void insert(int pos,int tot)
	{
		splay(find_kth(root,pos+1),NULL);
		splay(find_kth(root,pos+2),root);
		root->ch[1]->ch[0]=newnode();
		build(root->ch[1],root->ch[1]->ch[0],1,tot);
		update(root->ch[1]);update(root);
	}
	void delet(int pos,int tot)
	{
		splay(find_kth(root,pos),NULL);
		splay(find_kth(root,pos+1+tot),root);
		//Print(root);
		del(root->ch[1]->ch[0]);
		root->ch[1]->ch[0]=NULL;
		update(root->ch[1]);update(root);
	}
	void reverse(int pos,int tot)
	{
		splay(find_kth(root,pos),NULL);
		splay(find_kth(root,pos+1+tot),root);
		root->ch[1]->ch[0]->rev^=1;
		update(root->ch[1]);update(root);
	}
	void make_same(int pos,int tot,int c)
	{
		splay(find_kth(root,pos),NULL);
		splay(find_kth(root,pos+1+tot),root);
		node *x=root->ch[1]->ch[0];
		x->same=1;
		x->value=c;
		x->sum=c*x->size;
		x->MaxL=x->MaxR=x->MaxM=max(x->value,x->sum);
		update(root->ch[1]);update(root);
	}
	void get_sum(int pos,int tot)
	{
		if (tot==0)
		{
			printf("0n");
			return;
		}
		splay(find_kth(root,pos),NULL);
		//Print(root);cout<<endl;
		splay(find_kth(root,pos+1+tot),root);
		//Print(root);cout<<endl;
		node *x=root->ch[1]->ch[0];
		printf("%dn",x->sum);
	}
	void max_sum()
	{
		splay(find_kth(root,1),NULL);
		splay(find_kth(root,root->size),root);
		printf("%dn",root->ch[1]->ch[0]->MaxM);
	}
}S;
int main()
{
//	freopen("bzoj1500.in","r",stdin);
	cin>>n>>m;
	for (int i=1;i<=n;i++) cin>>a[i];
	S.insert(0,n);
	//S.Print(S.root);cout<<endl;
	for (int i=1;i<=m;i++)
	{
	//	cout<<i<<':';
		char s[10];
		scanf("%s",s);
		switch (s[2])
		{
			case'S':
				{
					int pos,tot;
					scanf("%d%d",&pos,&tot);
					for (int i=1;i<=tot;i++) scanf("%d",&a[i]);
					S.insert(pos,tot);
					break;
				}
			case'L':
				{
					int pos,tot;
					scanf("%d%d",&pos,&tot);
					S.delet(pos,tot);
					break;
				}
			case'K':
				{
					int pos,tot,c;
					scanf("%d%d%d",&pos,&tot,&c);
					S.make_same(pos,tot,c);
					break;
				}
			case'V':
				{
					int pos,tot;
					scanf("%d%d",&pos,&tot);
					S.reverse(pos,tot);
					break;
				}
			case'T':
				{
					int pos,tot;
					scanf("%d%d",&pos,&tot);
					S.get_sum(pos,tot);
					break;
				}
			case'X':
				{
					S.max_sum();
					break;
				}
		}
		//S.Print(S.root);cout<<endl;
	}
	return 0;
}

BZOJ 1034([ZJOI2008]泡泡堂BNB-田忌赛马)

1034: [ZJOI2008]泡泡堂BNB

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 682  Solved: 321
[Submit][Status][Discuss]

Description

 第XXXX届NOI期间,为了加强各省选手之间的交流,组委会决定组织一场省际电子竞技大赛,每一个省的代表队由n名选手组成,比赛的项目是老少咸宜的网络游戏泡泡堂。每一场比赛前,对阵双方的教练向组委会提交一份参赛选手的名单,决定了选手上场的顺序,一经确定,不得修改。比赛中,双方的一号选手,二号选手……,n号选手捉对厮杀,共进行n场比赛。每胜一场比赛得2分,平一场得1分,输一场不得分。最终将双方的单场得分相加得出总分,总分高的队伍晋级(总分相同抽签决定)。
作为浙江队的领队,你已经在事先将各省所有选手的泡泡堂水平了解的一清二楚,并将其用一个实力值来衡量。为简化问题,我们假定选手在游戏中完全不受任何外界因素干扰,即实力强的选手一定可以战胜实力弱的选手,而两个实力相同的选手一定会战平。由于完全不知道对手会使用何种策略来确定出场顺序,所以所有的队伍都采取了这样一种策略,就是完全随机决定出场顺序。 当然你不想这样不明不白的进行比赛。你想事先了解一下在最好与最坏的情况下,浙江队最终分别能得到多少分。

Input

输入的第一行为一个整数n,表示每支代表队的人数。 接下来n行,每行一个整数,描述了n位浙江队的选手的实力值。 接下来n行,每行一个整数,描述了你的对手的n位选手的实力值。 20%的数据中,1<=n<=10; 40%的数据中,1<=n<=100; 60%的数据中,1<=n<=1000; 100%的数据中,1<=n<=100000,且所有选手的实力值在0到10000000之间。

Output

包括两个用空格隔开的整数,分别表示浙江队在最好与最坏的情况下分别能得多少分。不要在行末输出多余的空白字符。

Sample Input

2

1

3

2

4

Sample Output

2 0

样例说明

我们分别称4位选手为A,B,C,D。则可能出现以下4种对战方式,最好情况下可得2分,最坏情况下得0分。

一 二 三 四

浙江 ??? 结果 浙江 ??? 结果 浙江 ??? 结果 浙江 ??? 结果

一号选手 A C 负 A D 负 B C 胜 B D 负

二号选手 B D 负 B C 胜 A D 负 A C 负

总得分 0 2 2 0



田忌赛马加强版。

尽可能让最弱的赢,最强的赢,都不行则最弱打最强

错误的贪心:

让最弱的能赢/平则赢/平,否则让其与最强的打

反例:

2

1 2 6 7

1 2 4 7

 ans1=6

反例ans1=5


最差情况:

容易发现2个队伍的总分一定(2-0,1-1,0-2)

 所以ans2=2n-B队最高分

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#include<cstdlib>
#include<cmath>
using namespace std;
#define MAXN (100000+10)
int n,a[MAXN],b[MAXN];
int calc()
{
	int i=1,j=1,k=n,l=n,ans=0;
	while (i<=k)
	{
		if (a[i]>b[j]) ans+=2,i++,j++;
		else if(a[k]>b[l]) ans+=2,k--,l--;
		else ans+=(a[i]==b[l]),i++,l--;
	}
	return ans;
}
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
	for (int i=1;i<=n;i++) scanf("%d",&b[i]);
	sort(a+1,a+1+n);sort(b+1,b+1+n);
	cout<<calc()<<' ';
	swap(a,b);
	cout<<2*n-calc()<<endl;
	return 0;
}