又是一次考試。
一如既往的墊底,收穫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,是一個時代的終結。