放球游戏(a^b博弈)

Problem 3 放球游戏(ball.cpp/c/pas)

【题目描述】

     Stas和Masha发明了一个游戏。游戏道具是a个两两不同的箱子和b个两两不同的皮球,Stas和Masha轮流操作,且每次操作新增一个完全不同的箱子或皮球。如果Stas或Masha操作了以后,把b个皮球放进a个箱子的方案数不小于n,那么这个人就会输掉。所有箱子和皮球都是不同的,可以有空的箱子。
  如果第一回合由Stas先操作,且Stas和Masha都按照最优策略进行游戏,那么是否会打平?如果不打平,谁会输??

【输入格式】

输入的第一行包含三个正整数a,b,n。

【输出格式】

如果Stas会输,输出'Stas'(不要输出引号);如果Masha会输,输出'Masha';   如果游戏会打平(也就是不结束),输出'Missing'。

【样例输入】

样例一:2 2 10

样例二:5 5 16808

样例三:3 1 4

样例四:1 4 10

 

【样例输出】

样例一:Masha

样例二:Masha

样例三:Stas

样例四:Missing

【数据范围】

对于10%的数据,n不超过10;
    对于30%的数据,n不超过10000。

对于100%的数据,1≤a≤10,000, 1≤b≤30, 2≤n≤1,000,000,000, a^b<n

博弈a^b=n

把a>1的所用情况记忆化(情况数少)

唯一平局的情况是

a=1 b=x 

(a+1)^b爆 

还有一种是

1^x 2^x爆 判奇偶

其实不记忆化也能过(汗-_-)。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<functional>
#include<cstdlib>
#include<cmath>
#include<iostream>
using namespace std;
#define MAXN (1000000000)
#define MAXA (10000+10)
#define MAXB (30+10)
long long a,b,n;
bool pow2(long long a,long long b)
{
	long long ans=1;
	for(int i=1;i<=b;i++)
	{
		ans*=a;
		if (ans>=n) return 0;
	}
	return 1;
}
int dfs(long long a,long long b) //a,b状态保证合法 0 Miss 1 Win -1 Lost
{
	if (a==1&&!pow2(a+1,b)) return 0;
	int flag=-1;
	if (a==1)
	{
		if (pow2(a+1,b)) flag=max(-dfs(a+1,b),flag);
		if (flag==1) return 1;
		if (pow2(a,b+1)) flag=max(-dfs(a,b+1),flag);
		return flag;
	}
	else
	{
		if (pow2(a,b+1)) flag=max(-dfs(a,b+1),flag);
		if (flag==1) return 1;
		if (pow2(a+1,b)) flag=max(-dfs(a+1,b),flag);
		return flag;
	}
}
int main()
{
	freopen("ball.in","r",stdin);
	freopen("ball.out","w",stdout);
	scanf("%d%d%d",&a,&b,&n);
	/*
	if (a==1&&!pow2(a+1,b))
	{

		return 0;
	}
	else if (b==1&&!dfs(a,b+1))
	{

	}
	*/
	int p=dfs(a,b);
	if (p==0) printf("Missingn");
	else if (p==-1) printf("Stasn");
	else printf("Mashan");
	return 0;
}

BZOJ 1502([NOI2005]月下柠檬树-Simpson积分)

1502: [NOI2005]月下柠檬树

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 250  Solved: 148
[Submit][Status][Discuss]

Description

李哲非常非常喜欢柠檬树,特别是在静静的夜晚,当天空中有一弯明月温柔地照亮地面上的景物时,他必会悠闲地坐在他亲手植下的那棵柠檬树旁,独自思索着人生的哲理。
李哲是一个喜爱思考的孩子,当他看到在月光的照射下柠檬树投在地面上的影子是如此的清晰,马上想到了一个问题:树影的面积是多大呢?
李哲知道,直接测量面积是很难的,他想用几何的方法算,因为他对这棵柠檬树的形状了解得非常清楚,而且想好了简化的方法。
李哲将整棵柠檬树分成了 n 层,由下向上依次将层编号为 1,2,...,n。从第 1到 n-1 层,每层都是一个圆台型,第 n 层(最上面一层)是圆锥型。对于圆台型,其上下底面都是水平的圆。对于相邻的两个圆台,上层的下底面和下层的上底面重合。第 n 层(最上面一层)圆锥的底面就是第 n-1 层圆台的上底面。所有的底面的圆心(包括树顶)处在同一条与地面垂直的直线上。李哲知道每一层的高度为h1,h2,...,hn,第 1 层圆台的下底面距地面的高度为 h0,以及每层的下底面的圆的半径 r1,r2,...,rn。李哲用熟知的方法测出了月亮的光线与地面的夹角为
alpha。

Input

文件的第1行包含一个整数n和一个实数alpha,表示柠檬树的层数和月亮的光线与地面夹角(单位为弧度)。 第2行包含n+1个实数h0,h1,h2,…,hn,表示树离地的高度和每层的高度。 第3行包含n个实数r1,r2,…,rn,表示柠檬树每层下底面的圆的半径。 上述输入文件中的数据,同一行相邻的两个数之间用一个空格分隔。 输入的所有实数的小数点后可能包含1至10位有效数字。

Output

输出1个实数,表示树影的面积。四舍五入保留两位小数。

Sample Input

2 0.7853981633

10.0 10.00 10.00

4.00 5.00

Sample Output

171.97

HINT

1≤n≤500,0.3<alpha<π 2,0<hi≤100,0<ri≤100。
 10%的数据中,n=1。
30%的数据中,n≤2。
60%的数据中,n≤20。
100%的数据中,n≤500。

这题是Simpson模版题。
有一个关键是圆的公切线的求法。
首先延长圆的切线求l,再求θ,最后用相似三角形。


#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define MAXN (500+10)
#define eps 1e-8
double h[MAXN],s[MAXN],r[MAXN],alpha,l1=0,r1=0;
double sqr(double x){return x*x;}
int n,size=0;
struct S
{
	double x,y,p,q;
}c[MAXN];
double f(double l)
{
	double t=0.0;
	for (int i=0;i<n;i++)
	{
		if (fabs(s[i]-l)<r[i]) t=max(t,sqrt(sqr(r[i])-sqr(s[i]-l)));
	}
	for (int i=1;i<=size;i++)
	{
		if (c[i].x<l&&l<c[i].p)	t=max(t,c[i].y+(c[i].q-c[i].y)*(l-c[i].x)/(c[i].p-c[i].x));
	}
	return t;

}
double simpson(double l,double r,double fl,double fmid,double fr)
{
	return (fl+4*fmid+fr)*(r-l)/6;
}
double rsimpson(double l,double r,double fl,double fmid,double fr)
{
	double m=(l+r)/2;
	double p=f((l+m)/2),q=f((m+r)/2);
	double x=simpson(l,r,fl,fmid,fr),y=simpson(l,m,fl,p,fmid),z=simpson(m,r,fmid,q,fr);
	if (fabs(x-y-z)<eps)
		return y+z;
	return rsimpson(l,m,fl,p,fmid)+rsimpson(m,r,fmid,q,fr);
}
int main()
{
	scanf("%d%lf",&n,&alpha);
	alpha=1/tan(alpha);
	for (int i=0;i<=n;i++)
	{
		scanf("%lf",&h[i]);
		if (i) h[i]+=h[i-1];
		s[i]=h[i]*alpha;
	}
	for (int i=0;i<n;i++)
	{
		scanf("%lf",&r[i]);
		l1=min(l1,s[i]-r[i]);
		r1=max(r1,s[i]+r[i]);
	}
	r[n]=0;
	for (int i=0;i<n;i++)
	{
		double d=s[i+1]-s[i];
		if (d>fabs(r[i]-r[i+1]))
		{
			c[++size].x=s[i]-r[i]*(r[i+1]-r[i])/d;
			c[size].y=sqrt(sqr(r[i])-sqr(c[size].x-s[i]));
			c[size].p=s[i+1]-r[i+1]*(r[i+1]-r[i])/d;
			c[size].q=sqrt(sqr(r[i+1])-sqr(c[size].p-s[i+1]));
		}
	}
	r1=max(r1,s[n]);
	printf("%.2lf",2*rsimpson(l1,r1,0,f((l1+r1)/2),0));
	return 0;
}

两个子序列(?标识符)

Problem 1 两个子序列(twosub.pas/c/cpp)

【题目描述】

将给定的n个长度为M的01串序列{a1,a2…an} 分为两个子序列{b1,b2…bk}和{c1,c2…cm},m+k=n,使|f(b1,b2…bk)|+|f(c1,c2…cm)|最小化。

f函数定义如下:

f(空序列)=空串
       f(s)=s
       f(s1,s2)=最小长度的有一个前缀等于s1并且有一个后缀等于s2的字符串。        f(a1,a2,…,an)=f(f(a1,a2,…,an-1),an)。

 

【输入格式】

第一行两个整数n。

接下来n行每行一个长度为M的01串,表示a1,a2...an。

 

【输出格式】

输出一个整数,表示答案。

 

【样例输入】

4
000
111
110
001

【样例输出】

8

【数据范围】

对于30%的数据,n<=20

对于60%的数据,n<=2000

对于100%的数据,1<=n<=200000,1<=M<=20

 

 这题要用后缀DP

f[i][j]表示非当前枚举点结尾的那个字符串结尾为i



#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cmath>
#include<iostream>
using namespace std;
#define MAXN (200000+10)
#define MAXM (20+10)
#define MAXSum (1<<20)
int n,m,f[MAXSum][MAXM],a[MAXN],bin[MAXM];
char s[MAXM];
int main()
{
	freopen("twosub.in","r",stdin);
	freopen("twosub.out","w",stdout);
	scanf("%d",&n);
	memset(f,128,sizeof(f));
	memset(a,0,sizeof(a));
	for (int i=1;i<=n;i++)
	{
		scanf("%s",s);
		m=strlen(s);
		for (int j=0;j<m;j++) a[i]=(a[i]<<1)+s[j]-48;
	}
	int tot=0;
	bin[0]=0;
	for (int i=1;i<=20;i++) bin[i]=(1<<i)-1;
	int ans=n*m;
	for (int i=2;i<=n;i++)
	{
		int k=m;
		while (k&&((bin[k]&a[i-1])!=a[i]>>(m-k)))
		{
		//	cout<<(bin[k]&a[i-1])<<' '<<a[i]<<m-k<<(a[i]>>(m-k))<<endl;
			k--;
		}
	//	cout<<k<<endl;
		ans-=k;
		int temp=0;
		for (int j=0;j<=m;j++) temp=max(temp,f[a[i]>>j][m-j]+m-j);
		for (int j=0;j<=m;j++) f[a[i-1]&bin[j]][j]=max(f[a[i-1]&bin[j]][j],temp-k);
	}
	int temp=0;
	for (int j=0;j<=m;j++)
		for (int i=0;i<=bin[j];i++) temp=max(temp,f[i][j]);
	cout<<ans-temp;
	return 0;
}

HDU 1075(What Are You Talking About-Trie的插入和查找)

What Are You Talking About

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/204800 K (Java/Others)
Total Submission(s): 8571    Accepted Submission(s): 2696



Problem Description
Ignatius is so lucky that he met a Martian yesterday. But he didn't know the language the Martians use. The Martian gives him a history book of Mars and a dictionary when it leaves. Now Ignatius want to translate the history book into English. Can you help
him?
 


Input
The problem has only one test case, the test case consists of two parts, the dictionary part and the book part. The dictionary part starts with a single line contains a string "START", this string should be ignored, then some lines follow, each line contains
two strings, the first one is a word in English, the second one is the corresponding word in Martian's language. A line with a single string "END" indicates the end of the directory part, and this string should be ignored. The book part starts with a single
line contains a string "START", this string should be ignored, then an article written in Martian's language. You should translate the article into English with the dictionary. If you find the word in the dictionary you should translate it and write the new
word into your translation, if you can't find the word in the dictionary you do not have to translate it, and just copy the old word to your translation. Space(' '), tab('t'), enter('n') and all the punctuation should not be translated. A line with a single
string "END" indicates the end of the book part, and that's also the end of the input. All the words are in the lowercase, and each word will contain at most 10 characters, and each line will contain at most 3000 characters.
 


Output
In this problem, you have to output the translation of the history book.
 


Sample Input
START from fiwo hello difh mars riwosf earth fnnvk like fiiwj END START difh, i'm fiwo riwosf. i fiiwj fnnvk! END
 


Sample Output
hello, i'm from mars. i like earth!
Hint
Huge input, scanf is recommended.
 


Author
Ignatius.L
 

Trie的插入和查找

话说也不难啊……

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<functional>
#include<cstdlib>
#include<iostream>
#include<cctype>
using namespace std;
#define MAXWordlen (10+10)
#define MAXLen (3000+10)
char s[MAXLen];
char word[MAXWordlen],word1[MAXWordlen];
struct node
{
	node *next[26+1];
	char t[MAXWordlen];
	node()
	{
		t[0]=0;
		for (int i=0;i<=26;i++) next[i]=NULL;
	}
}root;
void insert(char *str,char str1[])
{
	int len=strlen(str);
	node *p=&root;
	for (int i=0;i<len;i++)
	{
		if (p->next[str[i]-'a']==NULL) p->next[str[i]-'a']=new node();
		p=p->next[str[i]-'a'];
	}
	strcpy(p->t,str1);
}
node* find(int l,int r)
{
	node *p=&root;
	for (int i=l;i<=r;i++)
	{
		if (p->next[s[i]-'a']==NULL) return 0;
		p=p->next[s[i]-'a'];
	}
	if (strcmp(p->t,"")) return p;
	return 0;
}
int main()
{
	scanf("START");
	while (scanf("%s",word)&&strcmp(word,"END"))
	{
		scanf("%s",word1);
		insert(word1,word);
	}
	gets(word);
	scanf("START");
	gets(word);
	while (gets(s))
	{
		if (!strcmp(s,"END")) break;
		int len=strlen(s);
		s[len+1]=0;
		for (int i=0;i<len;i++)
		{
			if (islower(s[i]))
			{
				int j=i;
				while (islower(s[j+1])) j++;
				node *p=find(i,j);
				if (p) printf("%s",p->t);
				else
				{
					for (int k=i;k<=j;k++) printf("%c",s[k]);
				}
				i=j;
			}
			else printf("%c",s[i]);
		}
		printf("n");
	}
	return 0;
}

UVA 11292(Dragon of Loowater-勇者斗恶龙)

Problem C: The Dragon of Loowater

Once upon a time, in the Kingdom of Loowater, a minor nuisance turned into a major problem.

The shores of Rellau Creek in central Loowater had always been a prime breeding ground for geese. Due to the lack of predators, the geese population was out of control. The people of Loowater mostly kept clear of
the geese. Occasionally, a goose would attack one of the people, and perhaps bite off a finger or two, but in general, the people tolerated the geese as a minor nuisance.

One day, a freak mutation occurred, and one of the geese spawned a multi-headed fire-breathing dragon. When the dragon grew up, he threatened to burn the Kingdom of Loowater to a crisp. Loowater had a major problem.
The king was alarmed, and called on his knights to slay the dragon and save the kingdom.

The knights explained: "To slay the dragon, we must chop off all its heads. Each knight can chop off one of the dragon's heads. The heads of the dragon are of different sizes. In order to chop off a head, a knight
must be at least as tall as the diameter of the head. The knights' union demands that for chopping off a head, a knight must be paid a wage equal to one gold coin for each centimetre of the knight's height."

Would there be enough knights to defeat the dragon? The king called on his advisors to help him decide how many and which knights to hire. After having lost a lot of money building Mir Park, the king wanted to minimize
the expense of slaying the dragon. As one of the advisors, your job was to help the king. You took it very seriously: if you failed, you and the whole kingdom would be burnt to a crisp!

Input Specification:

The input contains several test cases. The first line of each test case contains two integers between 1 and 20000 inclusive, indicating the number n of heads that the dragon has, and the number m of
knights in the kingdom. The next n lines each contain an integer, and give the diameters of the dragon's heads, in centimetres. The following m lines each contain an integer, and specify the heights of the knights of Loowater, also in centimetres.

The last test case is followed by a line containing:

0 0

Output Specification:

For each test case, output a line containing the minimum number of gold coins that the king needs to pay to slay the dragon. If it is not possible for the knights of Loowater to slay the dragon, output the line:

Loowater is doomed!

Sample Input:

2 3
5
4
7
8
4
2 1
5
5
10
0 0

Output for Sample Input:

11
Loowater is doomed!

让最差的骑士优先杀最差的,

否则这个骑士不取。

可以证明这样取最优。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<functional>
#include<algorithm>
using namespace std;
#define MAXN (20000+10)
int n,m,a[MAXN],b[MAXN];
int main()
{
	while (scanf("%d%d",&n,&m)&&n&&m)
	{
		for (int i=1;i<=n;i++) scanf("%d",&a[i]);
		for (int i=1;i<=m;i++) scanf("%d",&b[i]);
		sort(a+1,a+n+1);sort(b+1,b+m+1);
		int i=1,j=1,cost=0;
		for (;i<=n&&j<=m;i++,j++)
		{
			if (b[j]>=a[i]) cost+=b[j];
			else i--;
		}
		if (i>n) cout<<cost<<endl;
		else cout<<"Loowater is doomed!n";
	}
	return 0;
}

人偶师(Gauss消元xor版-多解)

Problem 2 人偶师(alice.cpp/c/pas)

【题目描述】

n点m双向边的图,每个点有2个状态:开和关。每次操作改变一个点的状态,以及与其有边直接相连的点的状态。问开启所有点至少需要多少次操作。

【输入格式】

第一行2个整数n,m。

第二行n个整数,第i个数表示第i点的状态,0为关,1为开。

第3..m+2行,每行2个整数a,b,表示a和b直接相连,同一条边不会出现多次。

【输出格式】

第一行一个整数k表示最少的操作次数,所有数据保证至少有一组可行解。

第二行k个整数,表示操作的点的编号。

【样例输入】

4 3

1 1 0 0

2 3

1 3

2 4

【样例输出】

3

1 2 3

【数据范围】

对于30%的数据,1<=n<=10,0<=m<=40

对于60%的数据,1<=n<=30,0<=m<=100

对于100%的数据,1<=n<=40,0<=m<=500

这题还是高斯消元xor.

不同的是要考虑多解. 

高斯消元多解考虑方法:

Gauss();

dfs(n,1)//把值往回代

如果遇到a[i][i]==0,则分情况dfs.

这样做的好处是O(2^n)  

如果求出所有情况再往回代就是O(n^2*2^n) 


#include<cstdio>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cstdlib>
#include<cstring>
using namespace std;
#define MAXN (40+2)
#define MAXM (500+10)
int a[MAXN][MAXN];
int ans[MAXN],tot=MAXN,tot2=0,ans2[MAXN];
int n,m;
/*
void print(int a[MAXN][MAXN],int _n)
{
	for (int i=1;i<=_n;i++)
	{
		for (int j=1;j<=n+1;j++)
			printf("%d ",a[i][j]);
		printf("n");
	}
	printf("===n");
}

void res(int a[MAXN][MAXN])
{
	int tot2=0;
	for (int i=1;i<=n;i++) if (a[i][n+1]) ans2[++tot2]=i;
	if (tot2<tot)
	{
		tot=tot2;
		memcpy(ans,ans2,(tot+1)*sizeof(int));
	}
}
*/
void gauss()
{
	for (int i=1;i<=n;i++)
	{
		if (a[i][i]==0)
			for (int j=i+1;j<=n;j++) if (a[j][i]) {for (int k=1;k<=n+1;k++) swap(a[j][k],a[i][k]);break;}
		if (a[i][i]==0)	continue;
		for (int j=1;j<=n;j++)
			if (a[j][i]&&j!=i)
			{
				for (int k=1;k<=n+1;k++) a[j][k]^=a[i][k];
			}
//		print(a,n);
	}
//	res(a);
}
int uknow[MAXN],uq[MAXN],un=0;
bool b[MAXN]={0};
void dfs(int i,int tot2)
{
	if (tot2>=tot) return;
	if (i==0)
	{
		if (tot2<tot)
		{
			tot=tot2;
			memcpy(ans,ans2,sizeof(tot)*(tot+1));
		}
		return;
	}
	ans2[tot2+1]=i;
	if (a[i][i])
	{
		bool flag=a[i][n+1];
		for (int j=i+1;j<=n;j++) if (a[i][j]&b[j]) flag^=1;
		b[i]=flag;
		dfs(i-1,tot2+flag);
	}
	else
	{
		b[i]=1;
		dfs(i-1,tot2+1);
		b[i]=0;
		dfs(i-1,tot2);
	}

}
int main()
{
	freopen("alice.in","r",stdin);
	freopen("alice.out","w",stdout);
	memset(a,0,sizeof(a));
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&a[i][n+1]);
		a[i][n+1]^=1;
		a[i][i]=1;

	}
	for (int i=1;i<=m;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		a[u][v]=a[v][u]=1;
	}
//	print();
//	memcpy(a2,a,sizeof(a));
	gauss();
//	print(a,n);
	for (int i=1;i<=n;i++)
		if (!a[i][i]) uknow[++un]=i;
	dfs(n,0);
//	sort(ans+1,ans+1+tot);
	printf("%dn",tot);
	for (int i=1;i<tot;i++) printf("%d ",ans[i]);
	printf("%dn",ans[tot]);
	return 0;
}

POJ 1091(跳蚤-扩展欧几里德有解推论+容斥原理)

Language:
跳蚤
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 6911   Accepted: 1951

Description

Z城市居住着很多只跳蚤。在Z城市周六生活频道有一个娱乐节目。一只跳蚤将被请上一个高空钢丝的正中央。钢丝很长,可以看作是无限长。节目主持人会给该跳蚤发一张卡片。卡片上写有N+1个自然数。其中最后一个是M,而前N个数都不超过M,卡片上允许有相同的数字。跳蚤每次可以从卡片上任意选择一个自然数S,然后向左,或向右跳S个单位长度。而他最终的任务是跳到距离他左边一个单位长度的地方,并捡起位于那里的礼物。 
比如当N=2,M=18时,持有卡片(10, 15, 18)的跳蚤,就可以完成任务:他可以先向左跳10个单位长度,然后再连向左跳3次,每次15个单位长度,最后再向右连跳3次,每次18个单位长度。而持有卡片(12, 15, 18)的跳蚤,则怎么也不可能跳到距他左边一个单位长度的地方。 
当确定N和M后,显然一共有M^N张不同的卡片。现在的问题是,在这所有的卡片中,有多少张可以完成任务。 

Input

两个整数N和M(N <= 15 , M <= 100000000)。

Output

可以完成任务的卡片数。

Sample Input

2 4

Sample Output

12

Hint

这12张卡片分别是: 
(1, 1, 4), (1, 2, 4), (1, 3, 4), (1, 4, 4), (2, 1, 4), (2, 3, 4), 
(3, 1, 4), (3, 2, 4), (3, 3, 4), (3, 4, 4), (4, 1, 4), (4, 3, 4) 

Source

a1x1+a2x2+--anxn+a(n+1)M=1

则(a1,a2,..an,M)=1

所以用容斥原理计算出gcd≠1的情况的总数

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<functional>
using namespace std;
#define MAXN (15)
#define MAXM (100000000)
int n,m;
long long ans=0,temp=0;
int a[MAXM],tot=0;
long long pow2(long long a,int b)
{
	if (b==1) return a;
	else if (b%2)
	{
		long long p=pow2(a,b/2);
		return p*p*a;
	}
	else
	{
		long long p=pow2(a,b/2);
		return p*p;
	}
}
void dfs(int j,int c,int cost,int l)
{
	if (c==l)
	{
		int p=m/cost;
		if (l&1) ans+=pow2(p,n);
		else ans-=pow2(p,n);
		return;
	}
	for (int i=j+1;i<=tot+1-l+c;i++)
		dfs(i,c+1,cost*a[i],l);



}
int main()
{
	scanf("%d%d",&n,&m);
	int m2=m;
	for (int i=2;i<=(int)sqrt((double)m2);i++)
		if (0==m2%i)
		{
			a[++tot]=i;
			while (0==m2%i) m2/=i;
		}
	if (m2^1) a[++tot]=m2;
//	for (int i=1;i<=tot;i++) cout<<a[i]<<' ';
	for (int i=1;i<=tot;i++) dfs(0,0,1,i);
//	ans=pow(m,n)-ans;
	printf("%lldn",(long long)pow2(m,n)-ans);


	return 0;
}

POJ 1330(Nearest Common Ancestors-Lca模板题)

Nearest Common Ancestors
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 13559   Accepted: 7236

Description

A rooted tree is a well-known data structure in computer science and engineering. An example is shown below: 

 
In the figure, each node is labeled with an integer from {1, 2,...,16}. Node 8 is the root of the tree. Node x is an ancestor of node y if node x is in the path between the root and node y. For example, node 4 is an ancestor of node 16. Node 10 is also an ancestor
of node 16. As a matter of fact, nodes 8, 4, 10, and 16 are the ancestors of node 16. Remember that a node is an ancestor of itself. Nodes 8, 4, 6, and 7 are the ancestors of node 7. A node x is called a common ancestor of two different nodes y and z if node
x is an ancestor of node y and an ancestor of node z. Thus, nodes 8 and 4 are the common ancestors of nodes 16 and 7. A node x is called the nearest common ancestor of nodes y and z if x is a common ancestor of y and z and nearest to y and z among their common
ancestors. Hence, the nearest common ancestor of nodes 16 and 7 is node 4. Node 4 is nearer to nodes 16 and 7 than node 8 is. 

For other examples, the nearest common ancestor of nodes 2 and 3 is node 10, the nearest common ancestor of nodes 6 and 13 is node 8, and the nearest common ancestor of nodes 4 and 12 is node 4. In the last example, if y is an ancestor of z, then the nearest
common ancestor of y and z is y. 

Write a program that finds the nearest common ancestor of two distinct nodes in a tree. 

Input

The input consists of T test cases. The number of test cases (T) is given in the first line of the input file. Each test case starts with a line containing an integer N , the number of nodes in a tree, 2<=N<=10,000. The nodes are labeled with integers 1, 2,...,
N. Each of the next N -1 lines contains a pair of integers that represent an edge --the first integer is the parent node of the second integer. Note that a tree with N nodes has exactly N - 1 edges. The last line of each test case contains two distinct integers
whose nearest common ancestor is to be computed.

Output

Print exactly one line for each test case. The line should contain the integer that is the nearest common ancestor.

Sample Input

2
16
1 14
8 5
10 16
5 9
4 6
8 4
4 10
1 13
6 15
10 11
6 7
10 2
16 3
8 1
16 12
16 7
5
2 3
3 4
3 1
1 5
3 5

Sample Output

4
3

Source


Rt,纯粹无聊写的……(其实至今为止就写过2个………("▔□▔)/)

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define MAXN (10000+10)
#define Li (17)
int t,n,father[MAXN][Li];
int edge[MAXN],pre[MAXN],next[MAXN],size=0;
void addedge(int u,int v)
{
	edge[++size]=v;
	next[size]=pre[u];
	pre[u]=size;
}

int queue[MAXN],deep[MAXN],bin[Li];
void bfs()
{
	int head=1,tail=1;
	for (int i=1;i<=n;i++)
		if (!father[i][0]) {queue[1]=i;deep[i]=1;break;}
	while (head<=tail)
	{
		int &u=queue[head];
		for (int i=1;i<Li;i++)
		{
			father[u][i]=father[father[u][i-1]][i-1];
			if (father[u][i]==0) break;
		}
		for (int p=pre[u];p;p=next[p])
		{
			int &v=edge[p];
			deep[v]=deep[u]+1;
			queue[++tail]=v;
		}
		head++;
	}
}
int lca(int x,int y)
{
	if (x==y) return x;
	if (deep[x]<deep[y]) swap(x,y);
	int t=deep[x]-deep[y];
	for (int i=0;i<Li;i++)
		if (bin[i]&t)
		{
			x=father[x][i];
		}
	int i=Li-1;
	while (x^y)
	{
		while (father[x][i]==father[y][i]&&i) i--;
		x=father[x][i];y=father[y][i];
	}
	return x;
}
int main()
{
//	freopen("poj1330.in","r",stdin);
	scanf("%d",&t);
	for (int i=0;i<Li;i++) bin[i]=1<<i;

	while (scanf("%d",&n)!=EOF)
	{
		memset(pre,0,sizeof(pre));size=0;
		memset(father,0,sizeof(father));
		for (int i=1;i<n;i++)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			father[v][0]=u;
			addedge(u,v);
		}
		bfs();
		int x,y;
		scanf("%d%d",&x,&y);
		printf("%dn",lca(x,y));

	}
	return 0;
}

BZOJ 1977([BeiJing2010组队]次小生成树 Tree-LCA的位运算)

1977: [BeiJing2010组队]次小生成树 Tree

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 1176  Solved: 234
[Submit][Status][Discuss]

Description

小 C 最近学了很多最小生成树的算法,Prim 算法、Kurskal 算法、消圈算法 等等。 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了。小 P 说,让小 C 求出一 个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是 EM,严格次小生成树选择的边集是 ES,那么 需要满足:(value(e) 表示边 e的权值) 这下小
C 蒙了,他找到了你,希望你帮他解决这个问题。

Input

第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值 为z。

Output

包含一行,仅一个数,表示严格次小生成树的边权和。(数 据保证必定存在严格次小生成树)

Sample Input

5 6

1 2 1

1 3 2

2 4 3

3 5 4

3 4 3

4 5 6

Sample Output

11

HINT

数据中无向图无自环; 
50% 的数据N≤2 000 M≤3 000; 
80% 的数据N≤50 000 M≤100 000; 
100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9

Source

这题的关键就在于求Lca,记录路径上的最小与严格次小值.

用f[i][j]表示i的第2^j个儿子(0 表示 不存在)

那么f[i][j]=f[ f[i][ j-1] ][j-1]

dp[i][j]和dp0[i][j]表示点i到f[i][j]的最小和严格次小值(不存在=-1),那么只需特判即可.

int lca(int x,int y,int &nowdp,int &nowdp0)
{
	if (deep[x]<deep[y]) swap(x,y);
	int t=deep[x]-deep[y]; //差的数量
	for (int i=0;t;i++)
		if (t&bin[i])   //转化为位运算 bin[i]表示2<<i 把t看成2进制
		{
			x=f[x][i];
			t-=bin[i];
		}
	int i=Li-1; //Li 表示 最高存到2^(Li-1)个父亲
	while (x^y) //x和y不相等时
	{
		while (f[x][i]==f[y][i]&&i) i--; //当i==0时只能向上跳
		x=f[x][i];y=f[y][i];
	}
}

程序:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define MAXN (100000+10)
#define MAXM (600000+10)
#define Li (17)
#define INF (2000000000)
int edge[MAXM],pre[MAXM],weight[MAXM],next[MAXM],size=0;
int addedge(int u,int v,int w)
{
	edge[++size]=v;
	weight[size]=w;
	next[size]=pre[u];
	pre[u]=size;
}
int addedge2(int u,int v,int w)
{
	addedge(u,v,w);
	addedge(v,u,w);
}
int f[MAXN][Li]={0},dp[MAXN][Li]={0},dp0[MAXN][Li]={0},deep[MAXN],n,m;
struct E
{
	int u,v,w;
	friend bool operator<(E a,E b){return a.w<b.w;	}
}e[MAXM];
bool b[MAXM],vis[MAXN];
int queue[MAXN],head,tail;
void bfs()
{
	memset(vis,0,sizeof(vis));
	head=tail=1;queue[1]=1;vis[1]=1;deep[1]=0;
	while (head<=tail)
	{
		int &u=queue[head];
		if (u!=1)
		{
			for (int i=1;i<17;i++)
			{
				if (f[u][i-1])
				{
					f[u][i]=f[f[u][i-1]][i-1];
				}
				if (f[u][i]==0) break;
				if (f[u][i])
				{
					dp[u][i]=max(dp[u][i-1],dp[f[u][i-1]][i-1]);
				}
				if (i==1)
				{
					if (dp[u][0]!=dp[f[u][0]][0]) dp0[u][1]=min(dp[u][0],dp[f[u][0]][0]);
					else dp0[u][1]=-1;
				}
				else
				{
					dp0[u][i]=max(dp0[u][i-1],dp0[f[u][i-1]][i-1]);
					if (dp[u][i-1]!=dp[f[u][i-1]][i-1]) dp0[u][i]=max(dp0[u][i],min(dp[u][i-1],dp[f[u][i-1]][i-1]));
				}
			}
		}
		for (int p=pre[u];p;p=next[p])
		{
			int &v=edge[p];
			if (!vis[v])
			{
				queue[++tail]=v;
				vis[v]=1;deep[v]=deep[u]+1;
				f[v][0]=u;dp[v][0]=weight[p];dp0[v][0]=-1;
			}
		}
		head++;
	}
}
int bin[Li];
void check(int &nowdp,int &nowdp0,int c)
{
	if (c<=nowdp0) return;
	else if (nowdp0<c&&c<nowdp) nowdp0=c;
	else  if (c==nowdp) return;
	else if (nowdp<c) {nowdp0=nowdp;nowdp=c;}
}
int lca(int x,int y,int &nowdp,int &nowdp0)
{
	nowdp=nowdp0=-1;
	if (deep[x]<deep[y]) swap(x,y);
	int t=deep[x]-deep[y];
	for (int i=0;t;i++)
		if (t&bin[i])
		{
			check(nowdp,nowdp0,dp[x][i]);
			check(nowdp,nowdp0,dp0[x][i]);
			x=f[x][i];
			t-=bin[i];
		}
	int i=Li-1;
	while (x^y)
	{
		while (f[x][i]==f[y][i]&&i) i--;
		check(nowdp,nowdp0,dp[x][i]);
		check(nowdp,nowdp0,dp0[x][i]);
		check(nowdp,nowdp0,dp[y][i]);
		check(nowdp,nowdp0,dp0[y][i]);
		x=f[x][i];y=f[y][i];
	}
}
int father[MAXN];
long long sum_edge=0;
int getfather(int x)
{
	if (father[x]==x) return x;
	father[x]=getfather(father[x]);
	return father[x];
}
void union2(int x,int y)
{
	father[father[x]]=father[father[y]];
}
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++) father[i]=i;
	memset(b,0,sizeof(b));
	memset(next,0,sizeof(next));
	for (int i=0;i<Li;i++) bin[i]=1<<i;
	for (int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
	}
	sort(e+1,e+1+m);
	for (int i=1;i<=m;i++)
	{
		if (getfather(e[i].u)!=getfather(e[i].v)) {union2(e[i].u,e[i].v);addedge2(e[i].u,e[i].v,e[i].w);sum_edge+=e[i].w;	}
		else b[i]=1;
	}
	bfs();

	long long mindec=-1;
	for (int i=1;i<=m;i++)
		if (b[i])
		{
			int nowdp,nowdp0;
			lca(e[i].u,e[i].v,nowdp,nowdp0);
			if (nowdp==e[i].w) nowdp=nowdp0;
			if (nowdp==-1) continue;
			if (mindec==-1||mindec>e[i].w-nowdp) mindec=e[i].w-nowdp;
		}
	printf("%lldn",sum_edge+mindec);
	return 0;
}





POJ 3070(Fibonacci-矩阵幂)

Language:
Fibonacci
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 6733   Accepted: 4765

Description

 Fibonacci integer sequence指 F0 = 0, F1 = 1, and Fn = Fn − 1 + Fn − 2 for n ≥ 2. eg:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …

Fibonacci 的矩阵乘法求法如下

.

Given an integer n, 求 Fn mod 10000.

Input

多组数据,每行一个 n (where 0 ≤ n ≤ 1,000,000,000). 数据以 −1 结尾.

Output

对每组数据打印一行 Fn mod 10000).

Sample Input

0
9
999999999
1000000000
-1

Sample Output

0
34
626
6875

Hint

As a reminder, matrix multiplication is associative, and the product of two 2 × 2 matrices is given by

.

Also, note that raising any 2 × 2 matrix to the 0th power gives the identity matrix:

.

Source

正宗矩阵幂练手题

做了这题就差不多理解矩阵乘法了。

补充:递归一般能用矩阵乘法,如f[i]=g(f[i-1],f[i-2])...

    但是规划不行,如f[i]=max(....)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<functional>
using namespace std;
#define MAXN (1000000000)
#define F (10000)
struct M
{
	int a[3][3];
	M(int i){a[1][1]=a[1][2]=a[2][1]=1;a[2][2]=0;	}
	M(){memset(a,0,sizeof(a));	}
	friend M operator*(M a,M b)
	{
		M c;
		for (int i=1;i<=2;i++)
			for (int j=1;j<=2;j++)
				for (int k=1;k<=2;k++)
				{
					c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%F;
				}
		return c;
	}
	friend M pow(M a,int b)
	{
		if (b==1)
		{
			M c(1);
			return c;
		}
		else
		{
			M c=pow(a,b/2);
			c=c*c;
			if (b%2) return c*a;
			return c;
		}
	}
};
int n;
int main()
{
	while (cin>>n&&n!=-1)
	{
		if (n==0) printf("0n");
		else
		{
			M a=pow(M(1),n);
			printf("%dn",a.a[1][2]);
		}
	}
}