您的位置:首页 > 其它

2015百度之星复赛(hdu5258 - 5262)

2015-06-12 17:50 225 查看

数长方形

小度熊喜欢玩木棒。一天他在玩木棒的时候,发现一些木棒会形成长方形。小度熊可能是处女座吧,他只会将木棒横竖摆放,这样会形成很多长方形。现在给你一些横竖摆放的木棒,请你帮小度熊数一数形成了多少个长方形。

为了简化题目,一个木棒的端点不会在另一个木棒上,也就是说,木棒的端点不会在长方形上。

Input

第一行一个整数T,表示T组数据,不超过100组。

每组数据中,第一行是n,代表有多少个木棒,n不会超过25。接下来n行,每行4个整数x1,y1,x2,y2,代表木棒的坐标,绝对值不超过1000。

所有的木棒都是横竖摆放的,也就是说x1=x2或者y1=y2,没有长为0的木棒。

Output

对于每组测试数据,先输出一行

Case #i:

然后输出一个整数,代表有多少个长方形。

Sample Input

2
4
3 0 3 3
4 0 4 3
2 1 5 1
2 2 5 2
4
3 0 3 3
4 0 4 3
2 1 5 1
2 2 -5 2


Sample Output

Case #1:
1
Case #2:
0


暴力

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=50;
int N;
struct node
{
    int x1,y1,x2,y2;
} a[maxn];
int main()
{
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&N);
        for(int i=0; i<N; i++)
        {
            scanf("%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2);
            if(a[i].y1==a[i].y2&&a[i].x1>a[i].x2) swap(a[i].x1,a[i].x2);
            if(a[i].x1==a[i].x2&&a[i].y1>a[i].y2) swap(a[i].y1,a[i].y2);
        }
        int ans=0;
        for(int i=0; i<N; i++) if(a[i].x1==a[i].x2)
            for(int j=i+1; j<N; j++) if(a[j].x1==a[j].x2)
                for(int p=0; p<N; p++) if(a[p].y1==a[p].y2)
                    for(int q=p+1; q<N; q++) if(a[q].y1==a[q].y2)
                            if(a[i].x1!=a[j].x1&&a[p].y1!=a[q].y1)
                                if(a[p].y1>=max(a[i].y1,a[j].y1)&&a[p].y1<=min(a[i].y2,a[j].y2))
                                    if(a[q].y1>=max(a[i].y1,a[j].y1)&&a[q].y1<=min(a[i].y2,a[j].y2))
                                        if(a[i].x1>=max(a[p].x1,a[q].x1)&&a[i].x1<=min(a[p].x2,a[q].x2))
                                            if(a[j].x1>=max(a[p].x1,a[q].x1)&&a[j].x1<=min(a[p].x2,a[q].x2)) ans++;

        printf("Case #%d:\n%d\n",cas++,ans);
    }
    return 0;
}


弹吉他

Accepts: 495

Submissions: 1103

Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)

Problem Description

百小度立志在大学期间学会一门乐器,果不其然他买了一把吉他。



我们知道,弹吉他需要用左手手指在琴柄上按出各种和弦。通常情况下一首曲子需要按好多个和弦,下图就是C和弦的一种指法:



吉他谱里面,我们用1至4分别表示食指、中指、无名指、小拇指,上面表示食指按在2弦1品,中指按在4弦2品,无名指按在5弦3品。


而百小度现在正在挑战一首非常难的曲子,曲子里有 n 个和弦,而且每个和弦都需要用到四根手指头。转换和弦过程中,拇指每移动一根弦或者移动一品,都会消耗一点能量。百小度想知道,弹完这首曲子所需的能量总和最少是多少。


假定最开始左手的四根手指头依次位于“0弦”的1品到4品,“0弦”是虚拟的,表示手指头现在不按着任何弦。我们还考虑到这么一个问题,如果食指按在3品,那么中指不可能按在1品,也就是说序号大的手指所处的品位不能小于序号小的手指。


Input

第一行一个整数T,表示T组数据。

每组数据第一行一个正整数 n ,表示和弦数量。接下去 n 行,每行包含第4对不同的 a 、 b ,表示 a 弦 b 品。
数据范围


1≤n≤5000


1≤a≤6


1≤b≤4

Output

对于每组测试数据,先输出一行

Case #i:

然后输出一个整数,表示最小能量。


Sample Input

2
1
1 1 2 1 3 1 4 1
2
1 1 2 2 4 3 6 4
1 3 4 3 6 3 1 4


Sample Output

Case #1:
16
Case #2:
25


弹吉他

百小度立志在大学期间学会一门乐器,果不其然他买了一把吉他。



我们知道,弹吉他需要用左手手指在琴柄上按出各种和弦。通常情况下一首曲子需要按好多个和弦,下图就是C和弦的一种指法:



吉他谱里面,我们用1至4分别表示食指、中指、无名指、小拇指,上面表示食指按在2弦1品,中指按在4弦2品,无名指按在5弦3品。


而百小度现在正在挑战一首非常难的曲子,曲子里有 n 个和弦,而且每个和弦都需要用到四根手指头。转换和弦过程中,拇指每移动一根弦或者移动一品,都会消耗一点能量。百小度想知道,弹完这首曲子所需的能量总和最少是多少。


假定最开始左手的四根手指头依次位于“0弦”的1品到4品,“0弦”是虚拟的,表示手指头现在不按着任何弦。我们还考虑到这么一个问题,如果食指按在3品,那么中指不可能按在1品,也就是说序号大的手指所处的品位不能小于序号小的手指。


Input

第一行一个整数T,表示T组数据。

每组数据第一行一个正整数 n ,表示和弦数量。接下去 n 行,每行包含第4对不同的 a 、 b ,表示 a 弦 b 品。
数据范围


1≤n≤5000


1≤a≤6


1≤b≤4

Output

对于每组测试数据,先输出一行

Case #i:

然后输出一个整数,表示最小能量。


Sample Input

2
1
1 1 2 1 3 1 4 1
2
1 1 2 2 4 3 6 4
1 3 4 3 6 3 1 4


Sample Output

Case #1:
16
Case #2:
25


思路:暴力枚举手指品的状态

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
int t,n,ans,pe[4]={0,1,2,3},stat[25][4],dp[5010][24];
struct node
{
    int x,y;
    bool operator < (const node& rhs) const
    {
        if(x==rhs.x) return y<rhs.y;
        return x<rhs.x;
    }
};
struct node1
{
    node p[4];
}m[5010];
bool check(int i,int k)
{
    int pos[4];
    for(int l=0;l<4;l++)
    {
        int l1;
        for(l1=0;l1<4;l1++)
            if(stat[k][l1]==l)
                pos[l]=m[i].p[l1].y;
    }
    if(pos[0]<=pos[1]&&pos[1]<=pos[2]&&pos[2]<=pos[3]) return true;
    return false;
}
int cal(int i,int j,int k)
{
    int ret=0;
    for(int l=0;l<4;l++)
    {
        int l1,l2;
        for(l1=0;l1<4;l1++)
            if(stat[j][l1]==l)break;
        for(l2=0;l2<4;l2++)
            if(stat[k][l2]==l)break;
        ret+=abs(m[i].p[l1].x-m[i+1].p[l2].x)+abs(m[i].p[l1].y-m[i+1].p[l2].y);
    }
    return ret;
}
int main()
{
    scanf("%d",&t);
    for(int i=0;i<24;i++)
    {
        for(int j=0;j<4;j++)
            stat[i][j]=pe[j];
        next_permutation(pe,pe+4);
    }
    for(int cas=1;cas<=t;cas++)
    {
        ans=INF;
        scanf("%d",&n);
        memset(m,0,sizeof(m));
        memset(dp,INF,sizeof(dp));
        dp[0][0]=0;
        m[0].p[0].y=1;
        m[0].p[1].y=2;
        m[0].p[2].y=3;
        m[0].p[3].y=4;

        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<4;j++)
                scanf("%d%d",&m[i].p[j].x,&m[i].p[j].y);
        }
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<24;j++)
            {
                if(dp[i][j]==INF) continue;
                for(int k=0;k<24;k++)
                {
                    if(!check(i+1,k)) continue;
                    int gg=cal(i,j,k);
                    dp[i+1][k]=min(dp[i+1][k],dp[i][j]+gg);
                }
            }
        }
        for(int i=0;i<24;i++)
            ans=min(ans,dp
[i]);
        printf("Case #%d:\n%d\n",cas,ans);
    }
    return 0;
}


行路难

度度熊非常仰慕诗仙太白。这一天,它决定追寻仙人的踪迹,找到沧海中仙山之所在。

沧海之中有很多个岛屿,由于这些岛屿都和诗仙有一种神奇而莫名的关系,当你在一个岛屿上默念一句诗时,就会传送到另一个岛屿上去。度度熊现在在岛屿A上,它希望通过默念一系列诗句,能够被传送到岛屿B上。

如果可以,它还希望这些诗句连起来,字典序可以最小。此言尤美,是邪?

Input

第一行一个整数T,表示T组数据。

每组数据的第一行包含四个整数N(2≤N≤50),M(0≤M≤500),A,B。表示N个岛屿,和M个神奇的诗句传送方法,以及度度熊的起点和目的地(0≤A,B<N,A≠B)。

然后的M行,每行两个数字s,t(0≤s,t<N)和一个字符串S(字符串只包含小写字母,1≤S的长度≤6),表示默念S可以从s传送到t,注意s和t可以相同。并且可能有多种传送方法从一个岛屿到另一个岛屿,另外,如果在一个岛屿上默念一句诗可以传送到多个岛屿上,你可以随心,选择任意一个。

Output

对于每组测试数据输出两行:

第一行输出"Case #i:",其中 I 代表第 I 组测试数据。

然后输出可以完成传送的方法连接起来后字典序最小的传送诗句,如果不存在,无论是不存在字典序最小的,还是不存在这样的传送方法,都输出"Tough way!"(没有引号)。

Sample Input

3
2 2 0 1
0 0 b
0 1 a
2 2 0 1
0 0 a
0 1 b
4 4 0 1
0 3 hi
0 2 hey
3 1 rishi
2 1 jude


Sample Output

Case #1:
a
Case #2:
Tough way!
Case #3:
heyjude

Hint对于样例2,可以无限的利用a使字典序更小。


思路:可以用bellman-floyed或者暴力。bellman的时候要注意从终点到起点开始,这样才能保证字典序最少

bellman是从bc上站过来的

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <climits>
#include <deque>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <vector>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <algorithm>
#include <bitset>
#include <complex>
#include <string>
#include <utility>

using namespace std;

typedef long long LL;
typedef pair<int, int> Pii;
typedef pair<LL, LL> Pll;

#define foreach(it,s) for(__typeof(s.begin()) it=s.begin();it!=s.end();it++)

const int maxn = 50 + 5;
const int maxe = 500 + 5;

int n, m, s, t;
struct Tedge {
    int u, v;
    string w;
    Tedge(int u = 0, int v = 0, string w = ""):u(u), v(v), w(w){};
};
vector<Tedge> edge[maxn];
string dis[maxn];
bool vis[maxn];

string bf()
{
    int clk = 0;
    memset(vis, false, sizeof(vis));
    dis[t] = ""; vis[t] = true;
    while (1) {
        bool update = false;
        for (int ii=0;ii<n;ii++) {
            foreach(i, edge[ii]) 
                if (vis[i->v]) {
                    int u = i->u, v = i->v;
                    string tmp = i->w + dis[v];
                    if (!vis[u] || tmp < dis[u]) {
                        dis[u] = tmp;
                        update = vis[u] = true;
                        if (clk >= n - 1 && u == s) return "Tough way!";
                    }
                }
        }
        if (!update || ++clk > n * 6) break;
    }
    return vis[s] ? dis[s]: "Tough way!";
}

int main()
{
    int cas = 0;
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d%d%d", &n, &m, &s, &t);
        for (int i=0;i<n;i++) edge[i].clear();
        printf("Case #%d:\n", ++cas);
        for (int i=0;i<m;i++) {
            int u, v;
            char st[8];
            scanf("%d%d%s", &u, &v, st);
            edge[u].push_back(Tedge(u, v, st));
        }
        puts(bf().c_str());
    }

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
const int maxn=100;
int G[maxn][maxn];
int N,M,A,B;
set<pair<string,int>, less<pair<string,int> > > q;
vector<pair<string,int> > edge[maxn];
void add_edge(int u,int v,string s)
{
    edge[u].push_back(make_pair(s,v));
}
int main()
{
    int T,cas=1,u,v;
    string s;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d%d",&N,&M,&A,&B);
        memset(G,0,sizeof(G));
        for(int i=0;i<N;i++)
            G[i][i]=1,edge[i].clear();
        for(int i=1;i<=M;i++)
        {
            scanf("%d%d",&u,&v);
            cin>>s;
            add_edge(u,v,s);
            G[u][v]=1;
        }
        for(int k=0;k<N;k++)
        for(int i=0;i<N;i++)
            for(int j=0;j<N;j++)
                    if(G[i][k]&&G[k][j])G[i][j]=1;
        q.clear();
        q.insert(make_pair("",A));
        string tmp;
        while(A!=B)
        {
            if(q.empty())break;
            tmp=q.begin()->first;
            A=q.begin()->second;
            q.erase(q.begin());
            if(tmp.length()>N*6)break;
            for(int i=0;i<edge[A].size();i++)
            {
                int v=edge[A][i].second;
                if(!G[v][B])continue;
                string tmp1=tmp+edge[A][i].first;
                q.insert(make_pair(tmp1,v));
            }
        }
        printf("Case #%d:\n",cas++);
        if(A==B)cout<<tmp<<endl;
        else cout<<"Tough way!"<<endl;
    }
    return 0;
}


蜀道难

Accepts: 263

Submissions: 1306

Time Limit: 6000/3000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)

Problem Description

度度熊最近去四川游玩了一趟,在西南边,它发现了一个神奇的地方,那里有数不清的山,山脚的路组成了一个完美的圆,而山均匀的坐落在这个圆上。“此乃造物者之无尽藏也”,它大发诗情的感慨道。

山高皆不一,度度熊现在很想知道,距离最远的两座山顶是哪两座山。由于山顶不能直接到达,从一座山顶到另一座山顶的唯一方法是,先下山,沿着山脚的圆走到另一个山脚,再上山。当然,在山脚可以选择任意方向行走。

Input

第一行一个整数T,表示T组数据。

每组数据的第一行包含两个整数N(2≤N≤100000)
和R(1≤R≤109),表示山的个数和圆的半径。注意这里圆的半径不是R,而是NR/2PI
(PI=3.1415926…) 。

接着的一行包括N个整数Hi(1≤Hi<=109),表示山峰的高度。

Output

对第i组数据,输出

Case #i:

然后输出两座山峰的ID (从1开始),如果有多组答案,输出字典序最小的一对。

Sample Input

2
3 1
1 1 1
5 2
1 10 1 10 10


Sample Output

Case #1:
1 2
Case #2:
2 4


思路:对于这个点找他前面跟后面的个N/2个点中的最大值,我写了个线段树来更新,也可以直接单调队列

线段树:

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=200010;
int N;
int maxvid,maxvsum;
LL R;
int height[maxn];
struct IntervalTree
{
    LL sum[maxn<<2];
    int id[maxn<<2];
    void build(int o,int l,int r)
    {
        if(l==r)
        {
            sum[o]=R*(l-1)+height[l];
            id[o]=l;
            return ;
        }
        int mid=(l+r)>>1;
        build(o<<1,l,mid);
        build(o<<1|1,mid+1,r);
        pushup(o);
    }
    void pushup(int o)
    {
        if(sum[o<<1]<sum[o<<1|1])
        {
            sum[o]=sum[o<<1|1];
            id[o]=id[o<<1|1];
        }
        else
        {
            sum[o]=sum[o<<1];
            id[o]=id[o<<1];
        }
    }
    void query(int o,int l,int r,int q1,int q2)
    {
        if(q1<=l&&r<=q2)
        {
            if(sum[o]>maxvsum)
            {
                maxvsum=sum[o];
                maxvid=id[o];
            }
            return ;
        }
        int mid=(l+r)>>1;
        if(q1<=mid)query(o<<1,l,mid,q1,q2);
        if(q2>mid)query(o<<1|1,mid+1,r,q1,q2);
    }
}tree;
int main()
{
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%I64d",&N,&R);
        for(int i=1;i<=N;i++)
            scanf("%d",&height[i]);
        for(int i=1;i<=N;i++)
            height[i+N]=height[i];
        tree.build(1,1,N*2);
        LL anssum=0;
        int x,y,p;
        pair<int,int> ans=make_pair(N,N),tmp;
        for(int i=1;i<=N*2;i++)
        {
            int r=i+N/2,l=i-N/2;
            if(r>N*2||l<1)continue;
            maxvid=maxvsum=0;
            tree.query(1,1,N*2,i+1,r);
            x=maxvid;
            maxvid=maxvsum=0;
            tree.query(1,1,N*2,l,i-1);
            y=maxvid;
            if((i-y)*R+height[i]+height[y]>anssum)
            {
                anssum=(i-y)*R+height[i]+height[y];
                if(y>N)y-=N;
                p=i;
                if(p>N)p-=N;
                tmp=make_pair(min(y,p),max(y,p));
                ans=tmp;
            }
            else if((i-y)*R+height[i]+height[y]==anssum)
            {
                if(y>N)y-=N;
                p=i;
                if(p>N)p-=N;
                tmp=make_pair(min(y,p),max(y,p));
                if(tmp<ans)ans=tmp;
            }
            if((x-i)*R+height[x]+height[i]>anssum)
            {
                anssum=(x-i)*R+height[x]+height[i];
                if(x>N)x-=N;
                p=i;
                if(p>N)p-=N;
                tmp=make_pair(min(x,p),max(x,p));
                ans=tmp;
            }
            else if((x-i)*R+height[x]+height[i]==anssum)
            {
                if(x>N)x-=N;
                p=i;
                if(p>N)p-=N;
                tmp=make_pair(min(x,p),max(x,p));
                if(tmp<ans)ans=tmp;
            }
        }
        printf("Case #%d:\n",cas++);
        printf("%d %d\n",ans.first,ans.second);
    }
    return 0;
}


单调队列:

#include<bits/stdc++.h>
using namespace std;
const int maxn=200010;
typedef long long LL;
int height[maxn];
int N,q[maxn];
LL qh[maxn];
LL R;
int main()
{
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%I64d",&N,&R);
        for(int i=1;i<=N;i++)
        {
            scanf("%d",&height[i]);
            height[i+N]=height[i];
        }
        int ansx=0,ansy=0;
        LL ans=0;
        int s=1,t=0;
        for(int i=1;i<=2*N;i++)
        {
            while(s<=t&&(i-q[s])*2>N)s++;
            if(s<=t)
            {
                if(ans<height[i]+R*i+qh[s])
                {
                    ans=height[i]+R*i+qh[s];
                    ansx=q[s]>N?q[s]-N:q[s];
                    ansy=i>N?i-N:i;
                    if(ansx>ansy)swap(ansx,ansy);
                }
                else if(ans==height[i]+R*i+qh[s])
                {
                    int x=q[s]>N?q[s]-N:q[s];
                    int y=i>N?i-N:i;
                    if(x>y)swap(x,y);
                    if(ansx>x||ansx==x&&ansy>y)ansx=x,ansy=y;
                }
            }
            
            while(s<=t&&height[i]-R*i>qh[t])t--;
            t++;
            q[t]=i;
            qh[t]=height[i]-R*i;
        }
        printf("Case #%d:\n",cas++);
        printf("%d %d\n",ansx,ansy);
    }
    return 0;
}


最强密码

Accepts: 253

Submissions: 590

Time Limit: 10000/5000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)

Problem Description

由于近来密码库被盗的现象层出不穷,度度熊决定为自己的账号找一个最强密码。在研究了密码库很久之后,它总结出了一个规律:密码库中的所有密码都是一个“密码生成串”的子序列(某个序列的子序列是从最初序列通过去除某些元素但不破坏余下元素的相对位置(在前或在后)而形成的新序列)。

经过强大的计算集群夜以继日的工作,度度熊得到了这个“密码生成串”。现在它希望找到一个“最强密码”,不是这个“密码生成串”的子序列,并且长度最短。

任性的度度熊还希望知道这样的“最强密码”有多少个。幸运的是,“密码生成串”和“最强密码”都只包含小写字母。

Input

第一行一个整数T,表示T组数据 (1≤T≤100)

每组数据包含一个“密码生成串” (长度≤100000)

Output

对于每组测试数据输出两行:

第一行输出"Case #i:",其中 I 代表第 I 组测试数据。

第二行输出两个数,最短长度和该长度的“最强密码”个数(对 1 000 000 007 取模)。用空格分隔。

Sample Input

2
ab
abcdefghijklmnopqrstuvwxyzzyxwvutsrqponmlkjihgfedcba


Sample Output

Case #1:
1 24
Case #2:
3 6201


#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
using namespace std;
typedef long long LL;
const int maxn=100010;
const int MOD=1e9+7;
char str[maxn];
int dp[maxn];
int pos[30];
int nxt[maxn][30];
LL cnt[maxn];
int main()
{
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%s",str);
        int N=strlen(str);
        for(int i=0;i<26;i++)pos[i]=N+1;
        for(int i=N-1;i>=0;i--)
        {
            pos[str[i]-'a']=i+1;
            for(int j=0;j<26;j++)
                nxt[i][j]=pos[j];
        }
        dp[N+1]=0,dp
=1;
        for(int i=N-1;i>=0;i--)
        {
            int minv=N+1;
            for(int j=0;j<26;j++)
                minv=min(minv,dp[nxt[i][j]]+1);
            dp[i]=minv;
        }
        memset(cnt,0,sizeof(cnt));
        cnt
=26,cnt[N+1]=1;
        for(int i=N-1;i>=0;i--)
        {
            for(int j=0;j<26;j++)
                if(dp[i]==dp[nxt[i][j]]+1)
                {
                    cnt[i]+=cnt[nxt[i][j]];
                    if(cnt[i]>=MOD)cnt[i]-=MOD;
                }
        }
        printf("Case #%d:\n%d %I64d\n",cas++,dp[0],cnt[0]);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: