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;\)
\(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;
}