10月集训test3

所以不知道为什么test1和test2再次一起消失了。。。。
可能或许大概有时间会补上吧。
呵呵。
上题(那什么,最近降温好厉害。。好。。冷。。啊。。)

1.短文评估

为了维持生计,上学期期末迎考期间小可可在育红小学兼任了英语助教。首要任务就是协助英语教研室的老师们挑选合适的短文作为寒假作业布置给小朋友们,以提高他们的英语阅读能力。
挑选短文有一个评价标准。那就是同样长的文章,出现的单词越少越好,也就是说文章中词汇出现的频度越高越好。小可可根据思路设计了一个评估函数:
这里写图片描述

这个函数值越大,文章阅读难度越小。其中:T 是待评估的短文;Q(T)是短文中的单词数量,相同的单词重复计算;ψ(T)是短文 T 中单词构成的集合,单词是不区分大小写的,且该集合中没有重复的元素;f(w,T) 表示单词 w 在短文 T 中出现的次数。这里写图片描述表示短文 T 中出现的各个不同单词的出现次数的四次方和。
为了简化处理,同一个英语单词的不同形态(如复数、过去式、过去分词等)算作不同单词。除了英文字母,短文中出现的数字和标点符号都不算单词,只能算作分隔符。

例如短文:The International Olympic Committee (IOC) will decide the 2012 Olympic Games host in three years at a meeting in Singapore.

这篇短文的Q(T)=19。 是由 The,International,Olympic,Committee,IOC,will,decide,Games,host,in,three,years,at,a,meeting,Singapore等单词构成的集合(注意:The 和 the算同一个单词),这些单词在该短文中出现的次数分别是 2,1,2,1,1,1,1,1,1,2,1,1,1,1,1,1。
因此:
这里写图片描述

所以该短文的评估值
这里写图片描述

计算短文的评估值可不是一件轻松的事情,为了提高小可可的工作效率,请你帮她编写一个程序,只需要求出计算短文评估值所需要的 P(T) 和 Q(T) 。

输入格式

输入文件中所有的内容构成了待评估短文 T ,并且已知待评估短文的 Q(T)≤1000,任何一个单词的长度不超过 40 个字符,出现的次数不超过 50 。文章可能有很多段,段与段之间可能有一行空行,也可能没有。没有单词被拆分长两段。

输出格式

在一行输出两个整数,分别代表 P(T) 和 Q(T) 。两个整数之间用一个空格隔开。

样例数据1

输入
The International Olympic Committee (IOC) will decide the 2012 Olympic Games host in three years at a meeting in Singapore.

输出
61 19

样例数据 2

输入
The International Olympic Committee (IOC) will decide the 2012 Olympic Games host in three years at a meeting in Singa23pore.

输出
62 20

其实真的是模拟啊啊啊啊啊(画圈圈)。
但是,单词的定义真的是从输入就开始错。。果然还是一个一个字符的输入比较好,等到输入的什么字符也不是,break。
先算出Q(T),再将大写字母改为小写字母,然后先算出每个数的个数,算出不同个数出现的次数,最后计算P(T)。
呐,代码。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;

struct node
{
    int num;
    int son[26];
}trie[100000];
int ans,cnt,tot,len;
char c;
char s[100];

inline void zql()
{
    int pos=0;
    for(int i=0;i<len;i++)
    {
        if(!trie[pos].son[s[i]-'a'])
            trie[pos].son[s[i]-'a']=++tot;      //计算。。。各种个数
        pos=trie[pos].son[s[i]-'a'];
    }
    trie[pos].num++;
}

int main()
{
    //freopen("assess.in","r",stdin);
    //freopen("assess.out","w",stdout);

    memset(s,0,sizeof(s));
    while(c=getchar())
    {
        if(c<1||c>128)
            break;        //若不是字符,退出循环。
        len=0;
        while((c<'A'||c>'Z')&&(c<'a'||c>'z'))
        {
            c=getchar();
            if(c<1||c>128)
                break;
        }
        for(;c>='a'&&c<='z'||c>='A'&&c<='Z';c=getchar())
        {
            if(c>='A'&&c<='Z')
                c+=32;           //大写字母改小写。
            s[len++]=c;
        }
        if(len!=0)
        {
            cnt++;
            zql();
        }
    }
    for(int i=1;i<=tot;i++)
        if(trie[i].num)
            ans+=pow(trie[i].num,4);   //最终计算。
    cout<<ans<<" "<<cnt;
    return 0;
}

2.Route

一条直线上有 n 个人在走,有三个值来描述第i个人的行为:t[i],s[i],f[i],分别表示他出发的时间,他的起点位置和终点位置。假设每个人走的一样快,他们每个单位时间只会朝目的地走一个单位的距离。
当两个人相遇的时候,他们相互之间会打招呼。按照常理,两个人之间最多只会打一次招呼。
请算出每个人在他的旅程中要和多少个人打招呼。
注意:
(1)某个人在出发前是不在直线上的;
(2)到终点后,这个人也不再出现在直线上;
(3)如果 2 个人在同一个位置、同一时刻出发,属于相遇的情况。

输入格式

输入第一行包括一个整数 n 表示人数。
接下来 n 行,每行三个整数 t[i],s[i],f[i]。

输出格式

一行 n 个整数。第 i 个整数 a[i] 表示第 i 个人总共要和 a[i] 个人(总人数)打招呼。

样例数据

输入
3
1 1 10
5 8 2
9 9 10

输出
2 1 1

备注

【样例说明】

这里写图片描述

【数据范围】
对 30% 的输入数据 :n≤10
对 100% 的输入数据 :n≤1000,1≤t[i],s[i],f[i]≤1000000,s[i]≠f[i]

当时,想得太简单了,虽然实际上也没有多难。。。。。
唔,首先方向是关键,关系着两个人是同向还是相向。
若是同向,则相遇后后面的路程必然完全一样,则两人到达靠终点方向近的那个起点的时候,所用时间必然一样。
若是反向,先记录下两人的起点和终点一共四个值,只有中间一段重叠时二者才有可能相遇,则给四个点排个序,用b数组存储,若二者相遇,则必然有 abs(b[1]-b[2])<=2×(b[3]-b[2])&&abs(b[3]-b[4])<=2×(b[3]-b[2]) 恒成立。(具体的由于不方便画图,可以自己推呐。。)

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;

struct node
{
    int t,s,f,bb;
}a[1010];
int n,d,t1,t2,t3,t4;
int ans[1010],b[5];

inline int read()
{
    int i=0,f=1;
    char ch;
    for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    if(ch=='-') 
    {
        ch=getchar();
        f=-1;
    }
    for(;ch>='0'&&ch<='9';ch=getchar()) 
        i=(i<<3)+(i<<1)+ch-'0';
    return i*f;
}

inline bool zql(int x,int y)
{
    if(max(a[x].s,a[x].f)<min(a[y].s,a[y].f))  //排除掉必然不可能的
        return false;
    if(max(a[y].s,a[y].f)<min(a[x].s,a[x].f))
        return false;
    return true;
}

int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    {
        a[i].t=read();
        a[i].s=read();
        a[i].f=read();
        if(a[i].s<a[i].f)
            a[i].bb=1;
        else                     //记录方向。
            a[i].bb=2;
    }
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            if(zql(i,j)==true)
            {
                if(a[i].bb==a[j].bb)
                {
                    if(a[i].bb==1)
                        d=max(a[i].s,a[j].s);
                    else                         //同向。
                        d=min(a[i].s,a[j].s);
                    t1=a[i].t+abs(a[i].s-d);
                    t2=a[j].t+abs(a[j].s-d);
                    if(t1==t2)
                        ans[i]++,ans[j]++;
                }
                else
                {
                                                                                b[1]=a[i].s,b[2]=a[i].f,b[3]=a[j].s,b[4]=a[j].f;
                    sort(b+1,b+4+1);
                    t1=a[i].t+abs(a[i].s-b[2]);
                    t2=a[j].t+abs(a[j].s-b[2]);   //反向。
                    t3=a[i].t+abs(a[i].s-b[3]);
                    t4=a[j].t+abs(a[j].s-b[3]);
                    if(abs(t1-t2)<=2*(b[3]-b[2])&&abs(t3-t4)<=2*(b[3]-b[2]))
                        ans[i]++,ans[j]++;
                }
            }
    for(int i=1;i<=n;i++)
        cout<<ans[i]<<" ";
    return 0;
}

3.Work

假设现在离 noip 还有 m 天,有 n 个人要去参加比赛。他们每个人都有一个预定的训练量 r[i] ,所以每一天他们都抓紧时间练习。但是由于条件限制,第 i 天只有 t[i] 的时间可以练习。
我们都知道,一个人在开始干活以前总要浪费一些时间做一些杂七杂八的事情。现在我们假定第 i 个人每天在训练前浪费的时间是固定的,记为 d[i] 。这段浪费掉的时间过后,选手会专心致志训练,他们会充分利用剩下的时间。然而一个可能的情况时,一个人还在无所事事的时候,某一天的训练时间已经过去了,所以他那一天什么事情都没有做。
现在请问每个人在第几天的时候可以完成自己的训练任务。当然会存在志向远大但是很懒惰的人到最后也是做不完的情况。

输入格式

第一行两个整数 n,m ,表示人数和天数 。
接下来一行 m 个整数 t[i] 。
接下来 n 行每行两个整数 d[i],r[i] 。

输出格式

一行输出 n 个整数表示每个人在第几天可以完成自己的工作,如果完不成,输出 0 。

样例数据
输入 
3 3
4 2 5
1 3
2 5
3 4

输出
1 3 0

备注

【数据范围】
对 30% 的输入数据 :1≤n,m≤1000
对 100% 的输入数据 :1≤n,m≤ 200000;1≤t[i]≤1000000; 0≤d[i]≤1000000;1≤r[i]≤1000000

【注意事项】
如果某人浪费的时间超过一天,不需减去负的时间。

哦忘了说上面第二题用的是trie树,这一题呢,用的是树状数组。
嗯。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;

struct node
{
    int t,num,r;
}d[200103],man[200103];
int n,m;
int tim[200103],ans[200103];
long long sum[200103];

inline bool comp(const node &a,const node &b)
{
    if(a.t==b.t)
        return a.num<b.num;
    return  a.t>b.t;
}

inline int lowbit(int x)
{
    return x&(-x);
}

inline void build(int x,int val)
{
    for(int i=x;i<=m;i+=lowbit(i))
    {
        sum[i]+=val;
        tim[i]++;
    }
}

inline bool check(int x,int id)
{
    int res=0;
    for(int i=x;i>=1;i-=lowbit(i))
    {
        res+=sum[i];
        res-=man[id].t*tim[i];
    }
    return res>=man[id].r;
}

int main()
{
    //freopen("work.in","r",stdin);
    //freopen("work.out","w",stdout);

    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>d[i].t;
        d[i].num=i;
    }
    for(int i=1;i<=n;i++)
    {
        cin>>man[i].t>>man[i].r;
        man[i].num=i;
    }
    sort(d+1,d+m+1,comp);
    sort(man+1,man+n+1,comp);
    int cnt=1;
    for(int i=1;i<=n;i++)
    {
        while(man[i].t<d[cnt].t)
        {
            build(d[cnt].num,d[cnt].t);
            cnt++;
        }
        int l=1,r=m;
        ans[man[i].num]=0;
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(check(mid,i))
                ans[man[i].num]=mid,r=mid-1;
            else l=mid+1;
        }
    }
    for(int i=1;i<=n;i++)
        cout<<ans[i]<<" ";
    return 0;
}

真的好冷啊这几天。。。。
来自2017.10.9.

——我认为return 0,是一个时代的终结。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章