又是一次考试。
一如既往的垫底,收获10分。(共三道题)
首先是第一题:
1、减法(calc.c/cpp/pas)
【题目大意】
给出a 和 b,输出 a^b - b^a
【输入数据】
第一行两个数 a和 b,空格隔开
【输出数据】
一行一个数,表示 a ^ b – b ^ a
【输入样列】
2 3
【输出样列】
-1
【数据规模】
1<=a,b<=100
如题。(:
很明白的一道题,一眼看过去,公式都给好了。
然后看了一眼数据范围,1<=a,b<=100
很好,高精度……
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=2600;
struct BigNumber
{
int n,a[maxn];
BigNumber(int x=1){a[n=1]=x;}
void operator*=(int x)
{
for(int i=1;i<=n;++i)a[i]*=x;
for(int i=1;i<=n;++i)if(a[i]>=10000)
{
a[i+1]+=a[i]/10000;
a[i]%=10000;
}
while(a[n+1]>0)
{
++n;
if(a[n]>=10000)
{
a[n+1]+=a[n]/10000;
a[n]%=10000;
}
}
}//即定义结构体并压位,e.g.(1)(0)(0)(0)(0)(0)→(00001)(00000) [每个括号为数组中的一位]
void print()
{
printf("%d",a[n]);
for(int i=n-1;i;--i)printf("%04d",a[i]);puts("");
}
};
BigNumber operator-(BigNumber a,const BigNumber &b)
{
BigNumber c(0);
for(int i=1;i<=a.n;++i)
{
c.a[i]=a.a[i]-b.a[i];
if(c.a[i]<0)--a.a[i+1],c.a[i]+=10000;
}
c.n=1;
for(int i=a.n;i;--i)if(c.a[i]>0){c.n=i;break;}
return c;
}
bool operator<=(const BigNumber &a,const BigNumber &b)
{
if(a.n>b.n)return 0;
if(a.n<b.n)return 1;
for(int i=a.n;i;--i)if(a.a[i]<b.a[i])return 1;else if(a.a[i]>b.a[i])return 0;
return 1;
}//比较大小时用总和比较。
int main()
{
//freopen("calc.in","r",stdin);
//freopen("calc.out","w",stdout);
int a,b;
scanf("%d%d",&a,&b);
static BigNumber M,N;
for(int i=1;i<=b;++i)M*=a;
for(int i=1;i<=a;++i)N*=b;
if(N<=M)(M-N).print();
else
{
printf("-");
(N-M).print();
}
return 0;
}
(摘自标准题解)
很好很强大。
但是可以不用高精度,用它的思想。
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;
int a,b;
int x[220],y[220];
int zql()
{
for(int i=219;i>=0;i--)
{
if(x[i]==y[i])
continue;
return x[i]<y[i];
}
return false;
}
int main()
{
cin>>a>>b;
x[0]=y[0]=1;
for(int i=1;i<=b;i++)
{
int r=0;
for(int j=0;j<220;j++)
{
x[j]=x[j]*a+r;
r=x[j]/10;
x[j]%=10;
}
}
for(int i=1;i<=a;i++)
{
int r=0;
for(int j=0;j<220;j++)
{
y[j]=y[j]*b+r;
r=y[j]/10;
y[j]%=10;
}
}
if(zql())
{
for(int i=0;i<220;i++)
swap(x[i],y[i]);
cout<<"-";
}
int r=0;
for(int i=0;i<220;i++)
{
x[i]=x[i]-y[i]+r+10;
r=x[i]/10-1;
x[i]%=10;
}
for(r=219;r;r--)
if(x[r])
break;
for(int i=r;i>=0;i--)
cout<<x[i];
return 0;
}
r是进位,x[i],y[i]分别存储a^b和b^a,然后一位一位的相减。
果真清爽多了。
那么第二题。
2、tree.pas/c/cpp
【题目大意】
给出一个树,每个结点 i都有一个权值W[i]。现在要求你选出一些点,满足任意两个点之间都不能够有边相连,并且使得选出的点的总权值最大。
【输入数据】
第一行一个数 N表示结点数目
接下来一行N个数分别表示结点 1~N 的权值。
接下来 N-1行每行两个数表示一条边
【输出数据】
一个数表示最大的总权值
【Sample Input】
2
10 8
1 2
【Sample Output】
10
【数据规模】
30%:N<=10
100%:N<=10,0000,|W[i]|<=10^9
据说是比较简单的树形DP。
嗯,所以基本思路应该是,在一棵树上,若想要选出的任意两点无连边,选完某点后,既不能选它的父亲,也不能选它的儿子。
所以先建边。
inline void zql(int u,int v)
{
next[++tot]=first[u];
first[u]=tot;
en[tot]=v;
}
然后就可以开心的DFS了(认真脸)
inline void czh(int x)
{
int k;
v[x]=1;
g[x]=0,f[x]=w[x];
for(int i=first[x];i;i=next[i])
if(!v[k=en[i]])
{
czh(k);
g[x]+=max(f[k],g[k]);
f[x]+=g[k];
}
}
最后输出g[1]和f[1]的最大值即可。
总代码如下:
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;
typedef long long ll;
const ll ll_inf=1000000000000000011;
int n,tot;
int first[100003],next[200006],en[200006],w[100003];
ll g[100003],f[100003];
bool v[100003];
inline void zql(int u,int v)
{
next[++tot]=first[u];
first[u]=tot;
en[tot]=v;
}
inline void czh(int x)
{
int k;
v[x]=1;
g[x]=0,f[x]=w[x];
for(int i=first[x];i;i=next[i])
if(!v[k=en[i]])
{
czh(k);
g[x]+=max(f[k],g[k]);
f[x]+=g[k];
}
}
int main()
{
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
int u,v;
cin>>n;
for(int i=1;i<=n;i++)
cin>>w[i];
for(int i=1;i<n;i++)
{
cin>>u>>v;
zql(u,v),zql(v,u);
}
czh(1);
cout<<max(g[1],f[1])<<endl;
return 0;
}
最后我们来看看神奇的第三题。
3、cheer.pas/c/cpp
【题目描述】
Farmer John 变得非常懒,他不想再继续维护供奶牛之间供通行的道路。
道路被用来连接 N(5≤N≤10,000)个牧场,牧场被连续地编号为 1..N ,每一个牧场都是一个奶牛的家,FJ 计划除去 M(N-1≤M≤100,000)条道路中尽可能多的道路,但是还要保持任意两个牧场之间是连通的。
你首先要决定哪些道路是需要保留的 N-1 条道路。第 j 条双向道路连接了牧场 S[j] 和 E[j] (1≤S[j],E[j]≤N;S[j]≠E[j]),而且走完它需要 L[j](0≤L[j]≤1,000)的时间。没有两个牧场是被一条以上的道路所连接。
奶牛们非常伤心,因为她们的交通系统被削减了,所以你需要到每一个奶牛的住处去安慰她们。每次你到达第 i 个牧场的时候(即使你已经到过),你必须花去 Ci的时间和奶牛交谈。
安慰奶牛的出发牧场由你自己确定,并且在安慰完所有奶牛以后你必须回到起始位置。假设 Farmer John 采纳了你的建议,请计算出使所有奶牛都被安慰的最少时间。
【输入格式】
第 1 行:用空格隔开的两个整数 N 和 M 。
第 2..N+1 行:第 i+1 行包含了一个整数:C[i]。
第 N+2..N+M+1 行:第 N+j+1 行包含用空格隔开的三个整数:S[j],E[j] 和 L[j]。
【输出格式】
输出 1 行,一个整数,即所需要的总时间(包含和在你所在的牧场的奶牛的两次谈话时间)。
【样例数据】
输入
5 7
10
10
20
6
30
1 2 5
2 3 5
2 4 12
3 4 17
2 5 15
3 5 6
4 5 12
【输出】
176
【样例说明】
从牧场 4 出发,然后按照 4,5,4,2,3,2,1,2,4 的顺序来访问奶牛们,总共需要 176 个单位的时间。
大家都说这是裸奔的最小生成树……
然而天真的我并没有想到。
由题,每经过一条边,所花费的时间是边的权值和两点的值之和。
排序的时候要用总和来排序,而不仅仅是边的权值。
记住选定牧场后初始化时需加上起点的值,即将ans初始化为c[i]中的最小值。
废话不多说,上代码:
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;
struct node
{
int x;
int y;
int w;
}e[100005];
int n,m,ans;
int f[100005],c[100005];
inline bool comp(const node &a,const node &b)
{
return a.w<b.w;
}
inline int find(int x)
{
int u,v;
for(u=f[x];u!=f[u];u=f[u]);
for(;v!=u;)
{
v=f[x];
f[x]=u;
x=v;
}
return u;
}
int main()
{
freopen("cheer.in","r",stdin);
freopen("cheer.out","w",stdout);
int ans=~0u>>1; //尽量取一个很大的数。~为取反运算符,即将1变为0,0变为1,u指无符号数。其实本意就是取一个很大的数,便于后面与c[i]比较取最小值。
cin>>n>>m;
for(int i=1;i<=n;i++)
{
f[i]=i;
cin>>c[i];
ans=min(ans,c[i]);
}
for(int i=1;i<=m;i++)
{
cin>>e[i].x>>e[i].y>>e[i].w;
e[i].w=e[i].w*2+c[e[i].x]+c[e[i].y];
}
sort(e+1,e+1+m,comp);
for(int i=1;i<=m;i++)
{
int u,v;
u=find(e[i].x),v=find(e[i].y);
if(u!=v)
{
ans+=e[i].w;
f[u]=v;
}
}
cout<<ans<<endl;
return 0;
}
呐,Kruskal其实挺短的。
综上。
——我认为return 0,是一个时代的终结。