ACM Training DAY 1

https://vjudge.net/contest/321593
今天打了2018CCPC的网络赛,整个人毫无状态,极其颓废。

接下来按照题目难度顺序整理(学习):
D Find Integer
给出a和n,求使\(a^n+b^n=c^n\)成立的b和c,无解则输出-1 -1

虽说是裸的费马定理的板子,但是我真的不知道啊……
费马定理: \(n>2\)时,\(a^n+b^n=c^n\)无解
\(n=1\)时,\(a+b=c\),固输一个1和1+a即可
\(n=2\)时,\(a^2+b^2=c^2\),勾股数:
\(a\)为奇数时,\(tmp=a/2;\) \(b=(tmp+1)*tmp*2;\) \(c=b+1;\)
\(a\)为偶数时,\(tmp=a/2-1;\) \(b=(tmp+2)*tmp;\) \(c=b+2;\)

所以总之,这就是个特判固输题,但是……

#include<cstdio>
typedef long long ll;
using namespace std;
ll t,n,a,b,c,tmp;

int main()
{
	scanf("%lld",&t);
	while (t--)
	{
		scanf("%lld%lld",&n,&a);
		if (n==1) printf("1 %lld\n",a+1);
		else if (n>2 || n==0) printf("-1 -1\n");
		else
		{
			if (a&1)
			{
				tmp=a/2;
				b=(tmp+1)*tmp*2;
				c=b+1;
			}
			else
			{
				tmp=a/2-1;
				b=(tmp+2)*tmp;
				c=b+2;
			}
			printf("%lld %lld\n",b,c);
		}
	}
	return 0;
}

I Tree and Permutation
给出一个点数为n的树,求1~n的所有全排列对应到树上相应位置后,从1-2-...-n经过的边权的和

初步思路没有问题,求一条边两端分别有多少点,但是对于次数的计算不太明了。
事实上,如果这条边的一端为\(M\)个点,另一端为\(N-M\)个点,则经过他的次数就是\(M*(N-M)\),再算上不同的全排列:这两个点有\(N-1\)种,除了这两个点以外有\((N-2)!\)种,所以这条边造成的贡献就总共有\(L*2*M*(N-M)*(N-1)!\),其中\(L\)为该边的边长,2是因为两个点正反交换一下
那么每条边的贡献出来了之后,我们只要dfs求端点个数,在过程中求出答案就可以了

#include<cstdio>
#include<cstring>
#define N 100010
#define P 1000000007
typedef long long ll;
using namespace std;
int n,head[N],cnt,son[N];
ll sum;
struct hhh
{
	int nxt,to,w;
}e[N*2];

void add(int x,int y,int z)
{
	e[cnt].nxt=head[x];
	e[cnt].to=y;
	e[cnt].w=z;
	head[x]=cnt++;
}

void dfs(int x,int f)
{
	for (int i=head[x],v;i;i=e[i].nxt)
	{
		v=e[i].to;
		if (v==f) continue;
		dfs(v,x);
		sum+=1LL*2*son[v]*(n-son[v])%P*e[i].w%P;
		sum%=P;
		son[x]+=son[v];
	}
	son[x]++;
}

ll get(ll x)
{
	ll s=1;
	for (int i=2;i<=x;i++)
		s=s*i%P;
	return s;
}

int main()
{
	while (~scanf("%d",&n))
	{
		memset(head,0,sizeof(head));
		memset(son,0,sizeof(son));
		cnt=1;
		sum=0;
		for (int i=1,x,y,z;i<n;i++)
		{
			scanf("%d%d%d",&x,&y,&z);
			add(x,y,z);
			add(y,x,z); 
		}
		dfs(1,0);
		(sum*=get(n-1))%=P;
		printf("%lld\n",sum);
	}
	return 0;
} 

C Dream
要求重定义+和*,使得\((m+n)^p=m^p+n^p\)且存在\(q<p\)使得\({q^k | 0<k<p,k \in Z} = {k | 0<k<p , k \in Z}\)
其中p是质数。

因为p是质数,考虑费马小定理,\((m+n)^{p-1} \equiv 1 (mod p)\),所以\((m+n)^p \equiv m+n (mod p)\)
同样的,\(m^p=m\)\(n^p=n\),所以\(m^p+n^p=m+n\),所以\((m+n)^p=m^p+n^p\)可得。
综上,重定义的+和就是在\(mod p\)意义下的+和

(这怎么想到费马小定理嘛……

#include<cstdio>
using namespace std;
int t,p;

int main()
{
	scanf("%d",&t);
	while (t--)
	{
		scanf("%d",&p);
		for (int i=0;i<p;i++)
			for (int j=0;j<p;j++)
				printf("%d%c",(i+j)%p," \n"[j==p-1]);
		for (int i=0;i<p;i++)
			for (int j=0;j<p;j++)
				printf("%d%c",i*j%p," \n"[j==p-1]);
	}
	return 0;
}
posted @ 2020-09-16 14:19  Mrha  阅读(107)  评论(0编辑  收藏  举报