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;
}