我已经好久都没有写过博客了,这玩意儿真是一落下就补不回来了,把最近的一次考试附上吧
强迫症
问题描述
人行道铺着两行地砖,第一行每块的长度是A/B,第二行每块的长度是X/Y。两行砖块
第一块的一边是对齐的。
作为一个强迫症患者,看到这样的地砖你很不爽,于是就想知道,最少隔多少距离后两
行地砖的缝隙又会对齐。
输入格式
输入第一行包含一个整数T,表示测试点组数。
接下来T 行,每行两个分数,格式为A/B X/Y,两个分数中间用一个空格隔开。
输出格式
T 行,每行包含一个分数(若答案为整数则输出整数),表示每组数据的答案。分数必
须以最简形式输出。
样例输入
2
3/2 5/8
4/3 3/10
样例输出
15/2
12
数据范围
30%的数据A,B,X,Y<=20
70%的数据T<=10
100%的数据1<=A,B,X,Y,<=10,000,T<=100,000
直接暴力,当时开long long直接拿下。
#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
ll gcd(ll t,ll p)
{
if(p==0)return t;
return gcd(p,t%p);
}
int main()
{
freopen("tile.in","r",stdin);
freopen("tile.out","w",stdout);
int n;
scanf("%d",&n);
while(n--)
{
ll a,b,x,y;char z;
scanf("%d %c %d",&a,&z,&b);
scanf("%d %c %d",&x,&z,&y);
ll t=(b/gcd(b,y))*y;
a*=(t/b);x*=(t/y);
ll t2=(a/gcd(a,x))*x;
if(t2%t==0)printf("%I64d\n",t2/t);
else {
a=gcd(t2,t);
printf("%I64d/%I64d\n",t2/a,t/a);
}
}
return 0;
}
手套
问题描述
你现在有N对手套,但是你不小心把它们弄乱了,需要把它们整理一下。N对手套被一字排开,每只手套都有一个颜色,被记为0~N-1,你打算通过交换把每对手套都排在一起。由于手套比较多,你每次只能交换相邻两个手套。请你计算最少要交换几次才能把手套排整齐。
输入格式
输入第一行一个N,表示手套对数。
第二行有2N个整数,描述了手套的颜色。每个数都在0~N-1之间,且每个数字都会出现恰好两次。
输出格式
一行,包含一个数,表示最少交换次数。
样例输入
2
0 1 0 1
样例输出
1
数据范围
30%的数据N≤9;
60%的数据N≤1000;
100%的数据N≤200,000。
此题贪心法过70%,做法为:从i=1开始枚举,for循环找到与第i个相同的数字,移过来后继续。
正解:将数字出现的次序进行编号,如:
原数字串:2 1 0 1 2 0
编号后的:0 1 2 1 0 2
随后将编号后的数字串进行归并排序并求出逆序对。
代码:
#include<cstdio>
#include<iostream>
using namespace std;
int a[400005],t[400005],judge[400005],b[400005];
long long cnt,ans;
void gui(int l,int r)
{
if(l==r)return;
int m=l+(r-l)/2;
gui(l,m);
gui(m+1,r);
int i=l,j=m+1,k=l;
while(i<=m&&j<=r)
{
if(judge[i]<=judge[j])
t[k++]=judge[i++];
else
{
t[k++]=judge[j++];
ans+=(m-i+1);
}
}
while(i<=m)
t[k++]=judge[i++];
while(j<=r)
t[k++]=judge[j++];
for(i=l;i<=r;i++)
judge[i]=t[i];
}
int main()
{
freopen("gloves.in","r",stdin);
freopen("gloves.out","w",stdout);
int n;
scanf("%d",&n);
for(int i=1;i<=n+n;i++)
{
scanf("%d",&a[i]);
if(!b[a[i]])
{
judge[i]=++cnt;
b[a[i]]=cnt;
}
else judge[i]=b[a[i]];
}
gui(1,n+n);
printf("%I64d",ans);
}
星座
星座
问题描述
星空中有n颗星星,有n-1对星星间被人为地连上了线,每条连线有各自的长度。所有星星被连成了一个整体。现在,你要在星系中找到一个最大的十字形星座。即,你要找到两条星星构成的路径,使得它们恰好有一颗公共星(这颗公共星不能是某条路径的端点),且两条路径的长度和最大。
左图红线表示了一个合法的十字形星座,而右图的星座并不合法。
输入格式
第一行一个数n,表示星星的数量。
接下来n行,每行3个数x,y,z,表示第x颗星星和第y颗星星间有一条连线,它的长度是z。
输出格式
一行,包含一个整数,表示最大的路径长度和。若答案不存在,输出-1。
样例输入
10
3 8 6
9 3 5
1 9 2
4 8 6
2 3 3
10 4 8
5 9 5
7 2 3
6 9 1
样例输出
33
数据范围
20%的数据n<=1000
50%的数据n<=10,000
100%的数据n<=100,000,0<=z<=1000
题意我想很清楚,此处可直接暴力dfs,加数组du[]优化,如果du[i]≥4,那就搜这个点,复杂度O(n²)。
正解:任选一个树根,DP,f[i,0..3]分别表示从i开始,向下走到某个叶子为止最长、第二长、第三长、第四长的路径长度。从叶子向树根的顺序DP,每次用f[i,0]去尝试更新i的父亲,可以很方便地求出f数组。用g[i]表示以i为起点,第一步向i的父亲方向走的最长路径长度。第一步从i走到i的父亲fa[i]后,第二步有两种选择,第一种是继续往父亲走,则最长长度为g[fa[i]],第二种是向下走。为了使路径最长首选当然是f[fa[i],0],但如果i处在f[fa[i],0]对应的那条路径上,那就只能选择f[fa[i],1]了。有了f数组和g数组后,枚举公共点i,答案为max{f[i,0]+f[i,1]+f[i,2]+f[i,3] , g[i]+f[i,0]+f[i,1]+f[i,2]}。
网上找的,但意思很清楚。代码中使用的数组和题解有些不一样,以代码为准。
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int len[100005][5],zi[100005][5],tot,num,fa[100005],fcnt[100005];
int tov[200005],next[200005],head[100005],w[200005],du[100005];
bool judge[100005],bb;
int ans;
void add(int a,int b,int c)
{
tot++;
tov[tot]=b;next[tot]=head[a];
w[tot]=c;
head[a]=tot;
}
void dfs(int k)
{
int flag=k;
judge[k]=true;
int t=head[k];
while(tov[t])
{
if(!judge[tov[t]])
{
fa[tov[t]]=k;
judge[tov[t]]=true;
dfs(tov[t]);
if(w[t]+len[tov[t]][4]>len[k][4])
{
len[k][1]=len[k][2];
len[k][2]=len[k][3];
len[k][3]=len[k][4];
len[k][4]=w[t]+len[tov[t]][4];
zi[k][1]=zi[k][2];
zi[k][2]=zi[k][3];
zi[k][3]=zi[k][4];
zi[k][4]=tov[t];
}
else if(w[t]+len[tov[t]][4]==len[k][4])
{
len[k][1]=len[k][2];
len[k][2]=len[k][3];
len[k][3]=len[k][4];
zi[k][1]=zi[k][2];
zi[k][2]=zi[k][3];
zi[k][3]=zi[k][4];
zi[k][4]=tov[t];
}
else if(w[t]+len[tov[t]][4]<len[k][4]&&w[t]+len[tov[t]][4]>len[k][3])
{
len[k][1]=len[k][2];
len[k][2]=len[k][3];
len[k][3]=w[t]+len[tov[t]][4];
zi[k][1]=zi[k][2];
zi[k][2]=zi[k][3];
zi[k][3]=tov[t];
}
else if(w[t]+len[tov[t]][4]==len[k][3])
{
len[k][1]=len[k][2];
len[k][2]=len[k][3];
zi[k][1]=zi[k][2];
zi[k][2]=zi[k][3];
zi[k][3]=tov[t];
}
else if(w[t]+len[tov[t]][4]<len[k][3]&&w[t]+len[tov[t]][4]>len[k][2])
{
len[k][1]=len[k][2];
len[k][2]=w[t]+len[tov[t]][4];
zi[k][1]=zi[k][2];
zi[k][2]=tov[t];
}
else if(w[t]+len[tov[t]][4]==len[k][2])
{
len[k][1]=len[k][2];
zi[k][1]=zi[k][2];
zi[k][2]=tov[t];
}
else if(w[t]+len[tov[t]][4]<len[k][2]&&w[t]+len[tov[t]][4]>len[k][1])
len[k][1]=w[t]+len[tov[t]][4];
zi[k][1]=tov[t];
}
t=next[t];
}
}
void father_dfs(int k,int l)
{
int t=head[k];
if(k!=1)
{
if(zi[fa[k]][4]!=k)
fcnt[k]=max(fcnt[fa[k]]+l,max(fcnt[k],len[fa[k]][4]+l));
else if(zi[fa[k]][3]!=k)
fcnt[k]=max(fcnt[fa[k]]+l,max(fcnt[k],len[fa[k]][3]+l));
else if(zi[fa[k]][2]!=k)
fcnt[k]=max(fcnt[fa[k]]+l,max(fcnt[k],len[fa[k]][2]+l));
else if(zi[fa[k]][1]!=k)
fcnt[k]=max(fcnt[fa[k]]+l,max(fcnt[k],len[fa[k]][1]+l));
}
judge[k]=true;
if(fcnt[k]>=len[k][1]&&len[k][2]>0)
ans=max(ans,fcnt[k]+len[k][2]+len[k][3]+len[k][4]);
else if(len[k][1]>0)
ans=max(ans,len[k][1]+len[k][2]+len[k][3]+len[k][4]);
while(tov[t])
{
if(judge[tov[t]]==false)
{
father_dfs(tov[t],w[t]);
}
t=next[t];
}
}
int main()
{
freopen("cross.in","r",stdin);
freopen("cross.out","w",stdout);
int n;
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
du[a]++;du[b]++;
if(du[a]>=4||du[b]>=4)
bb=true;
add(a,b,c);
add(b,a,c);
}
if(bb!=true)
{
printf("-1");
return 0;
}
dfs(1);
memset(judge,false,sizeof judge);
father_dfs(1,0);
printf("%d",ans);
return 0;
}
ps:第一次使用markdown编辑器写博客,感觉很爽^ ^