2016.9.9

我已经好久都没有写过博客了,这玩意儿真是一落下就补不回来了,把最近的一次考试附上吧

强迫症

问题描述
人行道铺着两行地砖,第一行每块的长度是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编辑器写博客,感觉很爽^ ^

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值