Tim的模拟赛(提高组)

试题名称

时间限制

内存限制

测试点数目

每个测试点分值

买花

flower

1s

512M

10

10

购物

Shopping

1s

512M

10

10

配饰ornament

1s

512M

10

10

幸福的道路Race

1s

512M

10

10

买花Flower

【问题描述】

又到了一年一度的七夕节,逢此佳节,小T当然是要浪漫一下,去给小L买花。(虽然……TAT),今年,小T由于经费充足,因此他制定了一个特别的买花计划:买M束花,使得任意两束花的支数都不同,并且,尽管经费充足,也不能乱挥霍,因此小T决定对于这M束花,编号为1到M,第i束花恰好有i支花。

然而,计划总是赶不上变化。直到七夕前一天,小T才得知,小L最讨厌和M互质的数字,因此,小L会扔掉所有支数与M互质的花束。小T非常伤心,但是由于智商有限,小T只会按照原定计划进行。现在,小T的经费一共支持按照计划最多买N束花,但是,小T也可以选择买少于N束花。假如小T买了M束花,那么,第i束花仍然恰好有i支。

现在,小T希望聪明的你帮他制定一个最好的方案,使得被小L扔掉花束的比例尽可能小。

PS:看不懂题面的可以看这个:

即求一个小于等于M的数N,使得phi(N)/N最小,其中phi(N)是与N互质的数的个数。

例如phi(4)=2,因为1,3和4互质。

【输入格式】

一行一个正整数M。

【输出格式】

一行一个正整数N。

【样例输入】

10

【样例输出】

6

数据范围:

对于30%的数据,N<=1000

对于60%的数据,N<=1000,000,000

对于100%的数据,N<=10^40

#include <cstdio>
#include <cstring>
int notprime[5000000];
int prime[5000000];
char s[50];
int n[50];
int a[50];
int ans[50];
int tot;
bool compare(int a[],int n[]){
     if (n[0]>a[0]) return true;
     else if (n[0]<a[0]) return false;
     else{
          for (int i=a[0];i>0;i--){
              if (a[i]<n[i]) return true;
              else if (a[i]>n[i]) return false;
          }
     }
     return false;
}
void mul(int a[],int x){
     int c[50];
     int len=a[0]+7;
     int g=0;
     memset(c,0,sizeof(c));
     for (int i=1;i<=len;i++){
         c[i]=a[i]*x+g;
         g=c[i] / 10;
         c[i] %= 10;
     }
     while (c[len]==0) len--;
     c[0]=len;
     memcpy(a,c,sizeof(c));
}
int main(){
    freopen("flower.in","r",stdin);
    freopen("flower.out","w",stdout);
    scanf("%s",s);
    n[0]=strlen(s);
    for (unsigned int i=0;i<n[0];i++)
        n[n[0]-i]=s[i]-'0';
    notprime[1]=true;
    for (int i=2;i<=100000;i++){
        if (!notprime[i]){
                          for (int j=i+i;j<=2000000;j+=i) notprime[j]=true;
        }
    }
    for (int i=1;i<=2000000;i++){
        if (!notprime[i]) prime[++tot]=i;
    }
    a[0]=a[1]=1;
    for (int i=1;i<=tot;i++){
        if (compare(a,n)){
                          memcpy(ans,a,sizeof(ans));
                          mul(a,prime[i]);
        }else break;
    }
    for (int i=ans[0];i>0;i--){
        printf("%d",ans[i]);
    }
    putchar('\n');
    return 0;
}

 

购物shopping

【问题描述】

小T和小L都很喜欢购物,但是,众所周知,小T和小L都很懒,因此,在这么热的天,他们宁可在淘宝上买东西。现在,货架上有N件物品,由于小T和小L共用一台电脑,他们决定轮流购买自己喜欢的东西。由于小T和小L的审美完全不同,因此,每件物品对小T的价值为A_i,对小L的价值为B_i。因为小L和小T是好朋友,因此他们在满足自己利益的时候也会为别人着想。小T总是会选择对自己价值最大的物品,如果有多个,则选择其中对小L价值最小的。而小L就聪明很多(因为小L会算!= =||),他总是选择会使自己最后得到的物品总价值最多的物品,如果有多个,他会选择使得小L最后得到总价值也最多的物品。

现在,要求聪明的你帮助小L和小T计算按照他们的策略最后分别得到的物品的价值。

【输入格式】

第一行一个数N表示物品数。

第二行为“L”或者“T”,表示L或者T先选取物品。

第三到第N+2行,每行两个数A_i和B_i

【输出格式】

一行用空格隔开两个数P,Q分别表示小T和小L最后得到物品的总价值。

【样例输入】

4

L

100 80

70 80

50 80

30 50

【样例输出】

170 130

数据范围:

N<=100

 

配饰(ornament)

【问题描述】

但是小L想考验一下小T,所以,他给小T出了一个难题.

他拿出了他所有的配饰并摆成两列,如果两个配饰的型号一样并且出现在不同列中,那么我们就可以认为这两个配饰为情侣配饰.另外,由于某些不为人知的原因,我们规定,在顺序选取的情况下,每选定的一对配饰必须比前面选定的一对配饰的型号要大.小T最多能够选取多少对配饰呢?

【输入格式】

共四行

第一行一个数N 表示第一列配饰的个数

第二行N个数 分别表示第一列配饰的型号

第三行一个数M 表示第二列配饰的个数

第四行M个数 分别表示第二列配饰的型号

【输出格式】

仅一个数K,表示最多能选取的情侣配饰的对数.

【样例输入】

5

1 4 2 6 8

5

1 5 0 2 4

【样例输出】

2

数据范围:

30%的数据 n,m<=10

70%的数据 n,m<=100

100%的数据 n,m<=5000

#include <cstdio>
int n,m;
int a[5010],b[5010];
int f[5010][5010];
int ans;
int main(){
    freopen("ornament.in","r",stdin);
    freopen("ornament.out","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    scanf("%d",&m);
    for (int i=1;i<=m;i++){
        scanf("%d",&b[i]);
    }
    for (int i=1;i<=n;i++){
        int ma=0;
        for (int j=1;j<=m;j++){
            f[i][j]=f[i-1][j];
            if (a[i]==b[j]){
                            f[i][j]=ma+1;
            }
            if (a[i]>b[j] && ma<f[i-1][j]) ma=f[i-1][j];
            if (f[i][j]>ans) ans=f[i][j];
        }
    }
    printf("%d\n",ans);
    return 0;
}

幸福的道路(race)

【问题描述】

小T与小L终于决定走在一起,他们不想浪费在一起的每一分每一秒,所以他们决定每天早上一同晨练来享受在一起的时光.

他们画出了晨练路线的草图,眼尖的小T发现可以用树来描绘这个草图.

他们不愿枯燥的每天从同一个地方开始他们的锻炼,所以他们准备给起点标号后顺序地从每个起点开始(第一天从起点一开始,第二天从起点二开始……). 而且他们给每条道路定上一个幸福的值.很显然他们每次出发都想走幸福值和最长的路线(即从起点到树上的某一点路径中最长的一条).

他们不愿再经历之前的大起大落,所以决定连续几天的幸福值波动不能超过M(即一段连续的区间并且区间的最大值最小值之差不超过M).他们想知道要是这样的话他们最多能连续锻炼多少天(hint:不一定从第一天一直开始连续锻炼)?

现在,他们把这个艰巨的任务交给你了!

【输入格式】

第一行包含两个整数N, M(M<=10^9).

第二至第N行,每行两个数字Fi , Di, 第i行表示第i个节点的父亲是Fi,且道路的幸福值是Di.

【输出格式】

最长的连续锻炼天数

【样例输入】

3 2

1 1

1 3

【样例输出】

3

数据范围:

50%的数据N<=1000

80%的数据N<=100000

100%的数据N<=1000000

 

//树形DP+队列 
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#define INF 214748364
struct edge{
       int x,w,next;
}e[2000010];
int tot;
int n,m;
int fa[1000010];
int w[1000010];
int k[1000010];
int f[1000010][3];
int len[1000010];
int G[1000010][20];
int F[1000010][20];
int ans;
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
void add(int x,int y,int z){
     e[++tot].x=y;
     e[tot].w=z;
     e[tot].next=k[x];
     k[x]=tot;
}
void dp1(int x){
     for (int t=k[x];t;t=e[t].next){
         dp1(e[t].x);
         if (f[x][1]<f[e[t].x][1]+e[t].w){
                                          f[x][2]=f[x][1];
                                          f[x][1]=f[e[t].x][1]+e[t].w;
         }else if (f[x][2]<f[e[t].x][1]+e[t].w){
               f[x][2]=f[e[t].x][1]+e[t].w;
         }
     }
}
void dp2(int x){
     if (fa[x]!=0){
                    if (f[fa[x]][1]==f[x][1]+w[x])
                         f[x][0]=max(f[fa[x]][0],f[fa[x]][2])+w[x];
                    else f[x][0]=max(f[fa[x]][0],f[fa[x]][1])+w[x];
     }
     for (int t=k[x];t;t=e[t].next){
         dp2(e[t].x);
     }
}
int main(){
    freopen("race.in","r",stdin);
    freopen("race.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (int i=2;i<=n;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,i,y);
        fa[i]=x;
        w[i]=y;
    }
    dp1(1);
    dp2(1);
    for (int i=1;i<=n;i++){
        len[i]=max(f[i][0],f[i][1]);
        G[i][0]=F[i][0]=len[i];
//        printf("%d\n",len[i]);
    }
    for (int j=1;j<=(int)(log10((double)n)/log10(2.0));j++){
          for (int i=1;i<=(n-(1 << j)+1);i++){
              G[i][j]=min(G[i][j-1],G[i+(1 << (j-1))][j-1]);
              F[i][j]=max(F[i][j-1],F[i+(1 << (j-1))][j-1]);
          }
    }
    int head=1,tail=0;
    int mi=100000000,ma=-10000000;
    for (int i=1;i<=n;i++){
        tail++;
        if (len[tail]>ma) ma=len[i];
        if (len[tail]<mi) mi=len[i];
        while (ma-mi>m && head<tail){
              head++;
              int t=(int)(log10((double)(tail-head+1))/log10(2.0));
              ma=max(F[head][t],F[tail-(1 << t)+1][t]);
              mi=min(G[head][t],G[tail-(1 << t)+1][t]);
        }
        if (tail-head+1>ans) ans=tail-head+1;
    }
    printf("%d\n",ans);
    return 0;
}