NYIST-2019省赛训练个人积分赛第二场

A - Dinner

NBUT - 1217

题意

给你n个单词,从中找出和厨具有关的单词。
厨具有关的单词只有四个:bowl, knife, fork and chopsticks

很简单,就直接模拟就好了,控制一下输出的格式,比赛的时候没管太多。。代码写的有点长。。。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
char a[100005];
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        int flag=0;
        while(n--)
        {
            scanf("%s",a);
            if(strcmp(a,"bowl")==0)
            {

                if(!flag)
                    printf("%s",a);
                else
                    printf(" %s",a);
                    flag=1;
            }
            else if(strcmp(a,"knife")==0)
            {
                if(!flag)
                    printf("%s",a);
                else
                    printf(" %s",a);
                    flag=1;
            }
            else if(strcmp(a,"fork")==0)
            {
                if(!flag)
                    printf("%s",a);
                else
                    printf(" %s",a);
                    flag=1;
            }
            else if(strcmp(a,"chopsticks")==0)
            {
                if(!flag)
                    printf("%s",a);
                else
                    printf(" %s",a);
                    flag=1;
            }
        }
        printf("\n");
    }
    return 0;
}

·
·

You are my brother

NBUT - 1218

题意

有A和B两个在很久之前是一家人,由于过了太久,辈分有些乱,现在A想知道B是他平辈,低辈还是长辈
给你m条关系,每个关系有两个数字x,y,意思是y是x的父亲,A的数字代号是1,B的数字代号是2,如果B比A年轻,打印“You are my younger”。否则,如果B是A的长者,打印“You are my elder”。否则,打印“You are my brother”

每条关系都连接起来,比如存一下a的父亲是谁,连成一个树(线)一样的结构
从1(A)开始,找他的父亲,父亲的父亲…直到搜索到他们最大的公共祖宗,记录1到最大的祖宗中间一共有多少代,2页一样,比较他们两个到最大祖宗之间代数的大小

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int a[10005],ans;
void dfs(int u)//搜他们的父亲,父亲的父亲...直到那个最大的公共祖先
{
    if(u==-1)
        return ;
    ans++;
    dfs(a[u]);
}
int main()
{
    int n,x,y;
    while(~scanf("%d",&n))
    {
        memset(a,-1,sizeof(a));
        for(int i=1;i<=n;i++)
        {
            scanf("%d %d",&x,&y);
            a[x]=y;//存储关系
        }
        ans=0;
        dfs(1);
        int t1=ans;
        ans=0;
        dfs(2);
        int t2=ans;
        if(t1==t2)//比较他们之间的辈分层数
            printf("You are my brother\n");
        else if(t1>t2)
            printf("You are my elder\n");
        else
            printf("You are my younger\n");
    }
    return 0;
}

·
·

Time

NBUT - 1219

题意:

用 ”|”,”_”和” “打印123456789,每次输入四份数字,打印出来
大概思路就是一行一行的打,每行里一个数字一个数字的打
天哪,这个题真的是大型模拟爆炸现场。。。打的吐血… …比赛的时候也没管太多。。代码写的又臭又长。。。。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
void p1(int x)
{
    if(x==1)
    {
      printf("   ");
    }
    else if(x==2)
    {
        printf(" _ ");
    }
    else if(x==3)
    {
        printf(" _ ");
    }
    else if(x==4)
    {
        printf("   ");
    }
    else if(x==5)
    {
        printf(" _ ");
    }
    else if(x==6)
    {
        printf(" _ ");
    }
    else if(x==7)
    {
       printf(" _ ");
    }
    else if(x==8)
    {
        printf(" _ ");
    }
    else if(x==9)
    {
        printf(" _ ");
    }
    else if(x==0)
    {
        printf(" _ ");
    }
}
void p2(int x)
{
    if(x==1)
    {
      printf("  |");
    }
    else if(x==2)
    {
        printf(" _|");
    }
    else if(x==3)
    {
        printf(" _|");
    }
    else if(x==4)
    {
        printf("|_|");
    }
    else if(x==5)
    {
        printf("|_ ");
    }
    else if(x==6)
    {
        printf("|_ ");
    }
    else if(x==7)
    {
       printf("  |");
    }
    else if(x==8)
    {
        printf("|_|");
    }
    else if(x==9)
    {
        printf("|_|");
    }
    else if(x==0)
    {
        printf("| |");
    }
}
void p3(int x)
{
    if(x==1)
    {
      printf("  |");
    }
    else if(x==2)
    {
        printf("|_ ");
    }
    else if(x==3)
    {
        printf(" _|");
    }
    else if(x==4)
    {
        printf("  |");
    }
    else if(x==5)
    {
        printf(" _|");
    }
    else if(x==6)
    {
        printf("|_|");
    }
    else if(x==7)
    {
       printf("  |");
    }
    else if(x==8)
    {
        printf("|_|");
    }
    else if(x==9)
    {
        printf(" _|");
    }
    else if(x==0)
    {
        printf("|_|");
    }
}
void f1(int a,int b,int c,int d)
{
    p1(a);
    p1(b);
    p1(c);
    p1(d);
    printf("\n");
}
void f2(int a,int b,int c,int d)
{
    p2(a);
    p2(b);
    p2(c);
    p2(d);
    printf("\n");
}
void f3(int a,int b,int c,int d)
{
    p3(a);
    p3(b);
    p3(c);
    p3(d);
    printf("\n");
}
int main()
{
    int a,b,c,d;
    while(~scanf("%d",&a))
    {
        scanf("%d %d %d",&b,&c,&d);
        f1(a,b,c,d);
        f2(a,b,c,d);
        f3(a,b,c,d);
    }
    return 0;
}

·
·

D - SPY

NBUT - 1220

英语真的是爆炸 … … … … 到现在我也没搞懂什么间谍不间谍的,反正这道题要做的就是给你三行单词,从第二行中,找出第一行有的但是第三行没有的… … … 如此简单的题。。。硬是翻译不出来。。。。被自己气死。。。
用map模拟一下就好了

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<map>
using namespace std;
map<string,int>ma1;
map<string,int>ma2;
string aa[100005];
int ji[100005];
int main()
{
    int a,b,c;
    while(~scanf("%d %d %d",&a,&b,&c))
    {
        ma1.clear();
        ma2.clear();
        string x;
        for(int i=1;i<=a;i++)
        {
            cin>>x;
            ma1[x]++;
        }
        for(int i=1;i<=b;i++)
            {
                cin>>x;
                aa[i]=x;
            }
        for(int i=1;i<=c;i++)
        {
            cin>>x;
            ma2[x]++;
        }
        int ans=0;
        for(int i=1;i<=b;i++)
        {
            if(ma1[aa[i]]&&!ma2[aa[i]])
                {
                    ji[ans++]=i;
                }
        }
        if(ans==0)
            printf("No enemy spy\n");
        else
        {
            for(int i=0;i<ans;i++)
            {
                if(i==ans-1)
                {
                    cout<<aa[ji[i]];
                    printf("\n");
                }
                else
                {
                    cout<<aa[ji[i]];
                    printf(" ");
                }
            }
        }
    }
    return 0;
}

·
·

E - Intermediary

NBUT - 1221

题意

一共有n个相互都不认识的人(编号0~n-1),有m个中间介绍人(编号0—m-1)
如果介绍人z可以把x介绍给y那么第一次需要d元的介绍费,第二次需要d+e元介绍费,第三次及以上需要d+e+f元介绍费(介绍费都由x承担)(z可以把x介绍给y不代表z可以将y介绍给x)
现在0号员工想认识n-1号员工,x最少需要支付多少元的介绍费
输入:
第一行三个整数n,m,p员工数,介绍人数,介绍关系数
第二行m个数代表了这m个介绍人的e值
第三行m个数代表了这m个介绍人的f值
接下来p行 每行四个数x,y,z,d 代表x可以认识y通过第z个介绍人第一次需要花费d元

思路

这道题翻译出来也是费了老劲了… … …
这个最短路是可以想到的,但是我们需要记录每次的状态,第z个介绍人向x介绍y介绍了几次
因为一共只有9个介绍人,有3个状态,所以用三进制状压表示
dis[i][j]:第i个点的第j个状态下的需要花费的最小值
这其中状态的表示是这样的:每个介绍人介绍了多少次(第一个介绍人介绍了一次就是1,第二个介绍人介绍了一次就是3(三进制表示))
其他的就是最短路了

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
int th[15],c1[15],c2[15],fi[105],re[15];
int n,m,p,x,y,z,k,tot;
const int inf=0x3f3f3f3f;
int dis[105][20000];
struct node
{
    int v,nex,w,id;
};
node e[50005];
struct Node
{
    int u,cnt,dis;
    Node(int U,int Cnt,int Dis)
    {
        u=U;
        cnt=Cnt;
        dis=Dis;
    }
    bool operator < (const Node&x)const
    {
        return dis>x.dis;
    }
};
void add(int u,int v,int z,int w)
{
    e[tot].v=v;
    e[tot].id=z;
    e[tot].w=w;
    e[tot].nex=fi[u];
    fi[u]=tot++;
}
void dij()
{
    for(int i=0; i<n; i++)
        for(int j=0; j<th[m]; j++)
            dis[i][j]=inf;
    dis[0][0]=0;
    priority_queue<Node>q;//优先队列
    q.push(Node(0,0,0));
    while(!q.empty())
    {
        Node a=q.top();
        q.pop();
        if(a.dis>dis[a.u][a.cnt])
            continue;
        if(a.u==n-1)
        {
            printf("%d\n",a.dis);
            return ;
        }
        int u=a.u;
        for(int i=fi[u];i!=-1;i=e[i].nex)
        {
            int tmp=a.cnt;
            for(int j=0;j<9;j++)//第j个介绍了re【j】次
            {
                re[j]=tmp%3;
                tmp/=3;
            }
            int v=e[i].v,z=e[i].id,d=e[i].w,t=1;//t代表了这次要不要在加上一个状态,因为如果大于三次的话就不需要再加了
            if(re[z]==1)
                d+=c1[z];
            else if(re[z]==2)
            {
                d+=c2[z];
                t=0;
            }
            if(dis[v][a.cnt+t*th[z]]>a.dis+d)//松弛
            {
                dis[v][a.cnt+t*th[z]]=a.dis+d;
                q.push(Node(v,a.cnt+t*th[z],a.dis+d));
            }
        }
    }
    printf("-1\n");
}
int main()
{
    th[0]=1;
    for(int i=1; i<=9; i++)//初始化
        th[i]=th[i-1]*3;
    while(~scanf("%d %d %d",&n,&m,&p))
    {
        tot=0;
        memset(fi,-1,sizeof(fi));
        for(int i=0; i<m; i++)
            scanf("%d",&c1[i]);
        for(int i=0; i<m; i++)
            scanf("%d",&c2[i]);
        for(int i=1; i<=p; i++)
        {
            scanf("%d %d %d %d",&x,&y,&z,&k);
            add(x,y,z,k);
        }
        dij();
    }
    return 0;
}

·
·

Friends number

NBUT - 1223

题意

给你一个范围【a,b】,找出【a,b】之间有多找对朋友数。
朋友数的定义:假设x,y是一对朋友数,那么x的所有因子和等于y,y的所有因子和等于x

思路

真是让我长见识的一道题。。。如此的暴力竟然不超时
因为a,b的范围是5000000,所以先预处理出来1~5000000之间所有数的因子和(竟然不超时。。)
然后再预处理出来1~5000000 之间所有的朋友对数,一共只有71对,然后输入a,b,直接在这71对之间查找就好了

通过这道题发现:初始化用init()函数比较费时间,当时把init()里的初始化放在主函数里就过了,放在外面就T了… … … 还有就是用int比用long long 快好多,long long跑了900多MS,int只用了400多MS
还有if(…&&…&&…)这样的表达式顺序还是挺重要的,顺序不对会超时

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int f[5000005];
int a[500],b[500];
int tot;
int main()
{
    tot=0;
    for(int i=1; i<=5000000; i++)
    {
        int t=i+i;
        while(t<=5000000)
        {
            f[t]+=i;
            t+=i;
        }
    }
    for(int i=1; i<=5000000; i++)
    {
        int A=i,y=f[i];
        if(y>A&&y<5000000&&A==f[y])
        {
            a[tot]=A;
            b[tot]=y;
            tot++;
        }
    }
    int n,m;
    while(~scanf("%d %d",&n,&m))
    {
        int ans=0;
        for(int i=0; i<tot; i++)
        {
            if(a[i]>=n&&a[i]<=m&&b[i]>=n&&b[i]<=m)
                ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}

·
·

G - NEW RDSP MODE I

NBUT - 1225

题意

有n个数,1—n先按照从小到大的顺序排好,然后m次操作,一次操作的完整过程是:
1)初始序列叫做序列1
2)把奇数位的数字拿出来形成序列2
3)把序列2放在序列1的后面
例如 1 2 3 4 5一次操作之后变成2 4 1 3 5
问你在经过m次操作之后的那个序列前X个数字是多少

思路

在纸上画一画就知道,偶数位置下一次出现的位置是x/2,奇数位置下一次出现的位置是n/2+(x+1)/2
看到这个题知道有循环节的存在,以为这个循环节会有规律然而没有啥规律,就是每次模拟暴力算出来它的循环节,然后把先X个位置逆推出来

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int F_T(int n)//算循环节
{
    int p=1,ans=0;
    while(1)
    {
        ans++;
        if(p%2)
        {
            p=n/2+(p+1)/2;
        }
        else
        {
            p/=2;
        }
        if(p==1)
            return ans;
    }
}
int f(int x,int n,int m)//模拟逆推
{
    int p=x;
    for(int i=1;i<=m;i++)
    {
        if(p*2<=n)
            p=p*2;
        else
            p=(p-n/2)*2-1;
    }
    return p;
}
int main()
{
    int n,m,x;
    while(~scanf("%d %d %d",&n,&m,&x))
    {
        int t=F_T(n);
        for(int i=1;i<=x;i++)
        {
            printf("%d",f(i,n,m%t));
            if(i==x)
                printf("\n");
            else
                printf(" ");
        }
    }
    return 0;
}

·
·

H - A Simple Triangle

NBUT - 1226

题意:
按照题意打印三角形
Sample Input
3
5
6
Sample Output
1 2 3 4 5
2 4 6 8
3 6 9
4 8
5

1 2 3 4 5 6
2 4 6 8 10
3 6 9 12
4 8 12
5 10
6
好狗啊这个题。。如果当前的数字大于9就输出一个空格,否则输出两个空格,每行最后一个数字没有空格。。。。。。wa在这个空格上wa了五发。。。(英语硬伤,读了无数遍题)

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int main()
{
    int T,n;
    int flag=0;
    scanf("%d",&T);
    while(T--)
    {
        if(flag)
            printf("\n");
        flag=1;
        scanf("%d",&n);
            for(int i=1; i<=n; i++)
            {
                for(int j=1; j<=n-i+1; j++)
                {
                    if(j==n-i+1)
                    {

                        printf("%d\n",j*i);
                    }
                    else
                    {
                        if((i*j)>9)
                            printf("%d ",j*i);
                        else
                            printf("%d  ",j*i);
                    }
                }
            }
        }
    return 0;
}

·
·

I - Binary to Decimal

NBUT - 1227

题意

给你一个二进制转化为十进制,数据范围int之内,没啥说的,直接模拟

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
char a[10000];
int main()
{
    while(~scanf("%s",a))
    {
        int len=strlen(a);
        int sum=0;
        for(int i=len-1,j=0;i>=0;i--,j++)
        {
            if(a[i]=='1')
                sum+=(1<<j);
        }
        printf("%d\n",sum);
    }
    return 0;
}

·
·

J - Bored Three-God

NBUT - 1228

大数A+B

没啥说的,直接敲板子,他们说好像要判前导零,然而我也每判,直接就过了。。。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
char e1[100005],h1[100005];
int e[100005],h[100005],g[100005];
int main()
{
    while(~scanf("%s %s",e1,h1))
    {
        int a=strlen(e1);
        int b=strlen(h1);
        int l=a>b?a:b;
        memset(e,0,sizeof(e));
        memset(h,0,sizeof(h));
        memset(g,0,sizeof(g));
        for(int i=0;i<a;i++)
            e[i]=e1[a-1-i]-'0';
        for(int i=0;i<b;i++)
            h[i]=h1[b-1-i]-'0';
        int k=0;
        for(int i=0;i<l;i++)
        {
            g[i]=(e[i]+h[i]+k)%10;
            k=(e[i]+h[i]+k)/10;
        }
        if(k==1)
            printf("1");
        for(int i=l-1;i>=0;i--)
            printf("%d",g[i]);
        printf("\n");
    }
    return 0;
}

·
·

K - Socks

CodeForces - 731C

题意

Arseniy的妈妈给他搭配好了m天的袜子,可是有某些天的袜子颜色是不一样的,Arseniy不想穿颜色不一样的袜子,他有k个颜色的油漆,Arseniy可以把袜子染色,问你需要最少染色多少只袜子,使得Arseniy每天穿的袜子都是一个颜色的
输入:
第一行n,m,k分别代表Arseniy有n只袜子,m天,k个颜色的油漆
第二行n个数代表第i个袜子的颜色
接下来m行代表妈妈给Arseniy搭配的袜子,每行两个数,代表Arseniy今天穿的两只袜子是第几只袜子

思路

主要是题意太不好理解了。。。
用并查集把每天的袜子都集中的有限个集合中,查看每个集合里最多颜色的袜子,把其他的袜子染成这个颜色就可以了

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
int n,m,k,g,tot;
int w[200005],f[200005],vis[200005],c[200005],ma[200005];
vector<int>ve[200005];
struct node
{
    int v,nex;
};
node e[400005];
void add(int u,int v)
{
    e[tot].v=v;
    e[tot].nex=f[u];
    f[u]=tot++;
}
void dfs(int u)
{
    vis[u]=1;//把袜子放在第g个集合里
    ve[g].push_back(u);
    for(int i=f[u]; i!=-1; i=e[i].nex)
    {
        int v=e[i].v;
        if(!vis[v])
            dfs(v);
    }
}
int main()
{
    int x,y;
    memset(f,-1,sizeof(f));
    scanf("%d %d %d",&n,&m,&k);
    for(int i=1; i<=n; i++)
        scanf("%d",&w[i]);
    for(int i=1; i<=m; i++)
    {
        scanf("%d %d",&x,&y);
        add(x,y);
        add(y,x);
    }
    for(int i=1; i<=n; i++)
    {
        if(!vis[i])
        {
            g++;
            dfs(i);
        }
    }
    int ans=0;
    for(int i=1;i<=g;i++)
    {
        int len=ve[i].size();
        int sum=0;
        for(int j=0;j<len;j++)
        {
            int v=ve[i][j];
            ma[w[v]]++;//这里用map也是可以的,清空clear...当时还没学会map清空,用了数组模拟
            if(sum<ma[w[v]])
                sum=ma[w[v]];
        }
        ans+=(len-sum);
        for(int j=0;j<len;j++)//用memset好像会T
        {
            int v=ve[i][j];
            ma[w[v]]--;
        }
    }
    printf("%d\n",ans);
    return 0;
}

·
·

L - Wow! Such Conquering!

HDU - 4848

大概题意

一共有n个星球,给出你两两星球之间要达到的距离,每个星球有一个最晚到达的时间期限,问你从第一个星球开始,在每个星球最晚到达时间期限之内,到达每个星球的时间和是多少,如果到不了输出-1。

先用最短路跑出来两两星球到达的最小时间是多少,然后开始爆搜。。。。直接搜的话肯定超时,所以要加上剪枝。。。。
根据我的代码:time是到达u点所需要的时间,alltime是当前的总时间。
1)因为要算的是时间和,所以在深搜里,比如:(经过a点到到a+1,a+2…n点的时间都要加上1-a的时间,也就是(n-a)*time),如果alltime是搜到a点时之前的总时间,a点之后必须要有时间是(n-a)*time,所以alltime+(n-a)*time>sum的话,就没有搜下去的必要的,一定会超过现在的最优时间。
2)因为每个星球都有一个最后的时间期限,那么如果超过这个时间期限的话,就一定要剪枝。(这个具体看代码

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int e[45][45],n,ti[45];
int vis[45];
int sum;
void floyd()//求两两星球的最短时间
{
    for(int k=0; k<n; k++)
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
            {
                if(e[i][j]>e[i][k]+e[k][j])
                    e[i][j]=e[i][k]+e[k][j];
            }
}
void dfs(int cnt,int time,int alltime,int u)//time是当前到达u的时间,alltime是到达u时所有的总时间
{
    if(cnt==n)//搜到了n个点,取最优简化
    {
        sum=min(sum,alltime);
        return;
    }
    if(alltime+(n-cnt)*time>=sum)//剪枝
        return ;
    for(int i=1;i<n;i++)//剪枝
    {
        if(!vis[i])
        {
            if(time+e[u][i]>ti[i])//如果i点还未到达,time是1-u的所需时间,
                                 //通过u到达i的时间超过了i的最后期限,就没有必要搜下去了。
            return ;
        }
    }
    for(int i=1;i<n;i++)
    {
        if(!vis[i])
        {
            vis[i]=1;
            dfs(cnt+1,time+e[u][i],alltime+time+e[u][i],i);
            vis[i]=0;
        }
    }
}
int main()
{
    while(~scanf("%d",&n))
    {
        memset(vis,0,sizeof(vis));
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                scanf("%d",&e[i][j]);
        for(int i=1;i<n;i++)
            scanf("%d",&ti[i]);
        floyd();
        sum=0x3f3f3f3f;
        vis[0]=1;
        dfs(1,0,0,0);
        if(sum<0x3f3f3f3f)
           printf("%d\n",sum);
        else
            printf("-1\n");
    }
    return 0;
}


·
·

M - Lisp em

SCU - 4490

题意:
输入两行单词,问你第一个相同的单词是哪个,没有输出No
用map模拟一下就好了
比赛的时候忘记string可以直接比较,被自己蠢到。。。。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<iostream>
using namespace std;
int main()
{
    int T;
    string a;
    scanf("%d",&T);
    while(T--)
    {
        map<string,int>ma;
        while(1)
        {
            cin>>a;
            if(a[0]=='n'&&a[1]=='i'&&a[2]=='l')
                break;
            ma[a]=1;
        }
        string b;
        string c="0xffffff";
        int flag=0;
        while(1)
        {
            cin>>a;
            if(a[0]=='n'&&a[1]=='i'&&a[2]=='l')
                break;
            if(ma[a]&&!flag)
            {
                flag=1;
                b=a;
            }
        }
        if(!flag)
            printf("No\n");
        else
        {
            printf("Yes ");
            cout<<b;
            printf("\n");
        }
    }
    return 0;
}

·
·

N - Ultra-QuickSort

POJ - 2299

题意:

给出长度为n的序列,每次只能交换相邻的两个元素,问至少要交换几次才使得该序列为递增序列。

比赛的时候知道是归并排序但是很懵逼的是,时间不够。。。(只差了两分钟的我)
要使得序列从小到大排序,那么大的数要换到后面去,所以,我们只需要求当前数字后面有几个比它小的数,每个数都求一下,和就是答案
例如:
9 1 0 5 4
9 后面比它小的有 1 0 4 5 (4个)
1 后面比它小的有 0 (1个)
0 后面没有比它小的 (0个)
5 后面比它小的有 4 (1个)
4 后面没有比它小的 (0个)
所以4+1+1=6次;
交换的次数等于序列中的逆序对数

#include <stdio.h>
#include <algorithm>

int a[500000];
int d[500000];
unsigned long long count;

void mergeArray(int first, int mid, int last)
{
    int i = first, j = mid+1, k =0;
    int m = mid,   n = last;

    while(i<=m && j<=n){
        if (a[i] <= a[j]) {
            d[k++] = a[i++];
        }
        else {
            d[k++] = a[j++];
            count += m-i+1;   //记录
        }
    }

    while(i<=m) d[k++] = a[i++];
    while(j<=n) d[k++] = a[j++];

    for (int i=0;i<k; ++i) a[first+i] = d[i];
}
void mergeSort( int first, int end)
{
    if (first < end)
    {
        int mid = (first + end)/2;
        mergeSort(first, mid);
        mergeSort(mid+1, end);
        mergeArray(first, mid, end);
    }
}
int main()
{
    int num;
    while (true)
    {
        scanf("%d", &num);
        if (num <= 0) break;

        for (int i=0; i<num; ++i) scanf("%d", &a[i]);

        count = 0;
        mergeSort( 0, num-1);//归并排序
        printf("%lld\n", count);
    }

    return 0;
}

·
·

O - Pie

POJ - 3122

题意:

一共有n个味道的披萨,一共有f个朋友还有自己(也就是一共f+1个人),每个人都想要一样多的披萨,问每个人可以得到的最大的披萨体积是多少,不同味道的披萨不能给一个人

很经典的一个二分,及得好像做过,只是时间真的不够了。。。。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
int n;
int f;
double e[10000];
double pi=acos(-1.0);
int F(double mid)
{
    int ans=0;
    for(int i=1;i<=n;i++)
    {
            ans+=(int)(e[i]/mid);
    }
    if(ans>=(f+1))
        return 1;
    else
        return 0;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d",&n,&f);
        for(int i=1;i<=n;i++)
        {
            scanf("%lf",&e[i]);
            e[i]=e[i]*e[i]*pi;
        }
        sort(e+1,e+1+n);
        double l=0.0,r=e[n],ans;
        while(r-l>0.00001)
        {
            double mid=(l+r)/2;
            if(F(mid))
                {
                    ans=mid;
                    l=mid;
                }
            else
                r=mid;
        }
        printf("%.4f\n",ans);
    }
    return 0;
}

·
·

P - 无剑无我

HDU - 2547

题意
定义 f(x, y, m, n) = sqrt(xx + yy + mm + nn - 2mx - 2ny);
(其中x,y为位置变量,m,n为属性常量)
F = f(x, y, a, b) + f(x, y, c, d);
F的最小值
当时随便瞎搞了一下,感觉就是让一个为0 ,竟然过了,下来之后发现这就是两点之间距离公式,宛如一个智障。。。。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
int main()
{
    double a,b,c,d;
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lf %lf %lf %lf",&a,&b,&c,&d);
        double x=a;
        double y=b;
        double ans=sqrt((x-a)*(x-a)+(y-b)*(y-b))+sqrt((x-c)*(x-c)+(y-d)*(y-d));
        x=c;
        y=d;
        double sum=sqrt((x-a)*(x-a)+(y-b)*(y-b))+sqrt((x-c)*(x-c)+(y-d)*(y-d));
        printf("%.1f\n",ans<sum?ans:sum);
    }
    return 0;
}

·
·

Q - 水陆距离

HihoCoder - 1478

给定一个N x M的01矩阵,其中1表示陆地,0表示水域。对于每一个位置,求出它距离最近的水域的距离是多少。

矩阵中每个位置与它上下左右相邻的格子距离为1。

思路

就是把水域放进去,然后所有的水域一起搜,先到的一定是最短的
当时想起来了搜水域,没有想到同时搜。。。。哇。。。。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
int n,m;
char mapp[805][805];
int vis[805][805],e[805][805];
int nex[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
struct node
{
    int x,y,bu;
};
queue<node>q;
void dfs()
{
    node a;
    while(!q.empty())
    {
        a=q.front();
        q.pop();
        int xx=a.x;
        int yy=a.y;
        int bushu=a.bu;
        for(int i=0;i<4;i++)
        {
            int tx=xx+nex[i][0];
            int ty=yy+nex[i][1];
            if(vis[tx][ty])
                continue;
            if(tx<0||tx>=n||ty<0||ty>=m)
                continue;
            e[tx][ty]=bushu+1;
            vis[tx][ty]=1;
            node b;
            b.x=tx;
            b.y=ty;
            b.bu=bushu+1;
            q.push(b);
        }
    }
}
int main()
{
    node a;
    scanf("%d %d",&n,&m);
    for(int i=0;i<n;i++)
    {
        scanf("%s",mapp[i]);
        for(int j=0;j<m;j++)
        {
            if(mapp[i][j]=='0')
            {
                vis[i][j]=1;
                a.x=i;
                a.y=j;
                a.bu=0;
                q.push(a);
                e[i][j]=0;
            }
        }
    }
    dfs();
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            printf("%d%c",e[i][j],j==m-1?'\n':' ');
        }
    }
    return 0;
}`
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值