1. 程式人生 > 實用技巧 >ACM Training DAY 1

ACM Training DAY 1

https://vjudge.net/contest/321593#problem/A
今天打了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*M*(N-M)*(N-1)!\),其中\(L\)為該邊的邊長
那麼每條邊的貢獻出來了之後,我們只要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;
}