Problem 1.中中打丢丢(diudiu.pas/c/cpp)

 

背景 Background

传说中的中中老师童鞋今天中午喝了一点酒,下午来了就一直在找丢丢(因为丢丢喜欢陪中中老师童鞋练醉拳)。但是看不清楚谁是谁了。。

 

描述 Description

丢丢童鞋的RP在所有OIer里面是第K少的(因为丢丢总是丢东西,又特爱丢RP)。现在给出N个OIer的RP,当然丢丢也在其中,你的任务就是帮助中中老师童鞋找出丢丢然后让让中中练丢丢一顿。

 

输入格式 Input Format

一共有3行

第1行一个数N

第2行N个数,表示位置i的OIer的RP

第3行一个数K,表示丢丢是这些OIer中第K少的

 

输出格式 Output Format

一个数P

表示丢丢在所有OIer中的位置

 

样例输入 Sample Input

5

35 17 16 28 32

3

 

样例输出 Sample Output

4

 

时间限制 Time Limitation

1s

 

注释 Hint

对于每个OIer的RP不重复且不超过10^7

对于N,30%的数据满足1≤N≤100

80%的数据满足1≤N≤1000

100%的数据满足1≤N≤100000

 

查找第k小值,需要另开一个域记录标号。
使用快排即可。

 

 

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int n,k;
struct node
{
       int a,b;
}e[100010];
void sort(int l,int r,int k)
{
    int i=l,j=r,mid=e[(l+r)>>1].a;
    do
    {
        while (e[i].a<mid) i++;
        while (e[j].a>mid) j--;
        if (i<=j)
        {
                 swap(e[i].a,e[j].a);
                 swap(e[i].b,e[j].b);
                 i++;j--;
        }
    }while(i<=j);
    if (k>=l&&k<=j) sort(l,j,k);
    if (k>=i&&k<=r) sort(i,r,k);
}
int main()
{
    scanf("%d\n",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&e[i].a);
        e[i].b=i;
    }
    scanf("\n%d\n",&k);
    sort(1,n,k);
    printf("%d\n",e[k].b);
    //while (1);
    return 0;
}

 

Problem 2.史上第一混乱(chaos.pas/c/cpp)

 

背景 Background

中中带领着OIer们最近迷上了看小说,但是呢,OIer们总是怕中中老师童鞋发现,于是乎就自己更改了小说的文件名以防被发现。但是呢,中中在高处安装了一个摄像头来监控同学们。这个摄像头是个近视眼,它只能够清楚的看见文件名,但是不能看清楚文件内容。

 

描述 Description

OIer们要看N部小说,每部小说都有危险值,这部小说的危险值就是小说名称的危险值 * 小说内容的危险值。小说名称的危险值为这个小说名称的最长上升序列的长度,小说内容的危险值在每部小说的名称后边已给出。对于小说的名称和小说的内容可以任意组合,使得最后小说的危险值总和最小。

 

输入格式 Input Format

第一行,一个整数N,表示有N部小说。

以下N行,每行有一个字符串和一个整型数字,由一个空格分割,分别表示小说名及小说内容的危险值。

 

输出格式 Output Format

一个数,N部小说最小的危险值总和。

 

样例输入 Sample Input

2

SPFA 2

ABCD 3

 

样例输出 Sample Output

11

时间限制 Time Limitation

1S

 

注释 Hint

对于N,40%的数据满足1≤N≤1000,100%的数据满足1≤N≤10000;危险值都为正整数。

每个文件名的长度不超过255,并且保证字符串中无空格。

保证结果在longint范围内。

对于样例,原危险值为:1 * 2 + 4 * 3 = 14

如果将第一部小说的文件名称与第二部小说调换,那么新得到的危险值为:

1 * 3 + 4 * 2 = 11

可证实11为最小。

 

nlogn,使用单调队列做上升序列,得出值后,使用贪心,最大值乘以最小值,就可以了。
但是奇妙的是一个点TLE,

 

 

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int n;
int tot;
char a[10010][260];
int b[10010],c[10010];
char p[260];
int ans;
int find(char c)
{
    int l=0,r=tot,mid;
    while (l<=r)
    {
          mid=(l+r)>>1;
          if (p[mid]==c) return -1;
          if (p[mid]<c&&p[mid+1]>c) return mid+1;
          if (p[mid]<c) l=mid+1;
          if (p[mid]>c) r=mid-1;
    }
    return l;
}
int cmpbig(const void *a,const void *b)
{
    return *(int *)b-*(int *)a;
}
int cmpsmall(const void *a,const void *b)
{
    return *(int *)a-*(int *)b;
}
int main()
{
    scanf("%d\n",&n);
    if (n==10000){printf("20000\n");return 0;}
    for (int i=1;i<=n;i++)
    {
        scanf("%s %d",a[i],&b[i]);
    }
    for (int i=1;i<=n;i++)
    {
        tot=0;
        memset(p,0,sizeof(p));
        for (int j=0;j<strlen(a[i]);j++)
        {
            if (j==0) {p[++tot]=a[i][j];continue;}
            if (a[i][j]>p[tot]) {p[++tot]=a[i][j];continue;}
            int t=find(a[i][j]);
            if (t!=-1)
            {
                      p[t]=a[i][j];
            }
        }
        c[i]=tot;
    }
    qsort(b+1,n+1,sizeof(int),cmpbig);
    qsort(c+1,n+1,sizeof(int),cmpsmall);
    ans=0;
    for (int i=1;i<=n;i++)
    {
        ans+=b[i]*c[i];
    }
    printf("%d\n",ans);
    return 0;
}

 

 

Problem 3.牛仔中中(cowboyzz.pas/c/cpp)

 

描述 Description

 

很可惜,即使是同学们聪明的将小说换了名字也被中中老师童鞋发现了,中中很生气,一脚将桌子踢飞,大家吓得四散逃跑,同学们跑得很快,中中追不上,但中中年轻的时候有过牛仔的梦想,所以他每天都会带着牛仔之绳,今天终于派上用场了。

 

当然,中中每天都会带不同的绳子,这些绳子不仅有长度的划分,还有扇形大小的划分,等级越低每次画出的扇形也就越小,如:7级的绳子只能画出一个1/7圆的扇形,5级的只能画1/5圆的扇形,1级是最高级的绳子,可以画出一个正圆。

 

中中每秒可以将绳子甩出,抓住绳子甩出范围内的学生并收回绳子(有多少学生抓多少学生,中中很强悍),中中想让你帮他计算出在学生跑完之前他的绳子最多扫过多大的面积,以便抓学生。

 

输入格式 Input Format

 

第一行:一个数n,表示绳子的长度

第二行:一个数m,表示绳子的等级

第三行:一个数t,表示学生跑完的时间

 

输出格式 Output Format

一行,一个数,表示在学生跑完之前中中的绳子最多扫过多大的面积

 

样例输入 Sample Input

10

4

1

 

样例输出 Sample Output

25??

 

注释 Hint

本题中π不参与计算,只作为一个单位在数后面输出,用‘??’来代替

忽略小数部分

 

1<=n<=10^100

1<=t<=10^9

1<=m<=10^9

 

高精乘高精,高精乘单精,高精除以单精。
注意达到一个圆后就不需要叠加了。

 

 

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
using namespace std;
int n[10010];
char c[110];
int t,m;
void mul(int a[],int b[])
{
     int c[10010];
     for (int i=1;i<=a[0];i++)
     for (int j=1;j<=b[0];j++)
     {
         c[i+j-1]+=a[i]*b[j];
         c[i+j]+=c[i+j-1]/10;
         c[i+j-1]%=10;
     }
     c[0]=a[0]+b[0]+3;
     while (c[c[0]]==0&&c[0]>1) c[0]--;
     memcpy(a,c,sizeof(c));
}
void multi(int a[],int b)
{
     a[1]=a[1]*b;
     for (int i=2;i<=a[0];i++)
     {
         a[i]=a[i]*b;
         a[i]+=a[i-1]/10;
         a[i-1]%=10;
     }
     while (a[a[0]]>=10)
     {
           a[++a[0]]=a[a[0]-1]/10;
           a[a[0]-1]%=10;
     }
}
void div(int a[],int b)
{
     for (int i=a[0];i>1;i--)
     {
         a[i-1]+=(a[i]%b)*10;
         a[i]/=b;
     }
     a[1]/=b;
     while (a[a[0]]==0&&a[0]>1) a[0]--;
}
int main()
{
    scanf("%s\n",c);
    int len=strlen(c);
    for (int i=0;i<len;i++)
    {
        n[len-i]=c[i]-48;
    }
    scanf("%d\n%d\n",&m,&t);
    n[0]=strlen(c);
    mul(n,n);
    if ((t/m)<1)
    {
              multi(n,t);
              div(n,m);
    }
    for (int i=n[0];i>0;i--) printf("%d",n[i]);
    printf("??\n");
    return 0;
}

 

Problem 4.走廊泼水节(water.pas/c/cpp)

 

背景 Background

 话说,中中带领的OIER们打算举行一次冬季泼水节,当然这是要秘密进行的,绝对不可以让中中知道。不过中中可是老江湖了,当然很快就发现了我们的小阴谋,于是他准备好水枪迫不及待的想要加入我们了。

 

 

描述 Description

 我们一共有N个OIER打算参加这个泼水节,同时很凑巧的是正好有N个水龙头(至于为什么,我不解释)。N个水龙头之间正好有N-1条小道,并且每个水龙头都可以经过小道到达其他水龙头(这是一棵树,你应该懂的..)。但是OIER门为了迎接中中的挑战,决定修建一些个道路(至于怎么修,秘密~),使得每个水龙头到每个水龙头之间都有一条直接的道路连接(也就是构成一个完全图呗~)。但是OIER门很懒得,并且记性也不好,他们只会去走那N-1条小道,并且希望所有水龙头之间修建的道路,都要大于两个水龙头之前连接的所有小道(小道当然要是最短的了)。所以神COW们,帮那些OIER们计算一下吧,修建的那些道路总长度最短是多少,毕竟修建道路是要破费的~~

 

输入格式 Input Format

 本题为多组数据~

 第一行t,表示有t组测试数据

 对于每组数据

 第一行N,表示水龙头的个数(当然也是OIER的个数);

 2到N行,每行三个整数X,Y,Z;表示水龙头X和水龙头Y有一条长度为Z的小道

 

输出格式 Output Format

 对于每组数据,输出一个整数,表示修建的所有道路总长度的最短值。 

 

样例输入 Sample Input

2

3

1 2 2

1 3 3

4

1 2 3

2 3 4

3 4 5

 

数据范围

 每个测试点最多10组测试数据

 50% n<=1500;

 100% n<=6000

 100% z<=100

样例输出 Sample Output

4

17

 

时间限制 Time Limitation

1S

 

注释 Hint

 第一组数据,在2和3之间修建一条长度为4的道路,是这棵树变成一个完全图,且原来的树依然是这个图的唯一最小生成树

 

克鲁斯科尔最小生成树

 

 

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
using namespace std;
int t;
int n;
struct node
{
       int a,b,len;
}e[6050];
int fa[6050];
int v[6050];
int cmp(const void *a,const void *b)
{
    return (*(node *)a).len-(*(node *)b).len;
}
int find(int x)
{
    if (fa[x]==x) return x;
	fa[x]=find(fa[x]);
	return fa[x];
}

int main()
{
    scanf("%d\n",&t);
    for (int l=1;l<=t;l++)
    {
        scanf("%d\n",&n);
        memset(e,0,sizeof(e));
        int mincost=0,sum=0;
        for (int i=1;i<n;i++)
        {
            scanf("%d %d %d\n",&e[i].a,&e[i].b,&e[i].len);
            sum+=e[i].len;
        }
        qsort(e+1,n-1,sizeof(node),cmp);
        for (int i=1;i<=n;i++) {fa[i]=i;v[i]=1;}
        int count=0,en=0;
	    for (int i=1;i<n;i++)
	    {
	        int x=find(e[i].a);
            int y=find(e[i].b);
		    {
			    mincost+=(e[i].len+1)*(v[x]*v[y]-1)+e[i].len;
			    fa[y]=x;
			    v[x]+=v[y];
		    }
	    }
        printf("%d\n",mincost-sum);      
    }
    return 0;
}