*TEST 3 for NOIP 哈希有毒

头更更大

这个10月完就要去搞NOIP了。。。

10月30天也就3次测试。。。为保佑进省一我还是每次测试玩都写个总结。。


boomshakalaka。。。第一题写炸。。。
第一题开四个哈希数组最后都还要爆两个。。。也是没谁了。。有毒。。
第二题不知道为什么没几个做起。。不是小学奥数吗。。
第三题暴力得了30分。

TEST 3 for NOIP(160/300)

短文评估【安徽省选2003】(30/100)

题目背景
AHOI2003

题目描述
为了维持生计,上学期期末迎考期间小可可在育红小学兼任了英语助教。首要任务就是协助英语教研室的老师们挑选合适的短文作为寒假作业布置给小朋友们,以提高他们的英语阅读能力。

挑选短文有一个评价标准。那就是同样长的文章,出现的单词越少越好,也就是说文章中词汇出现的频度越高越好。小可可根据思路设计了一个评估函数:

这里写图片描述

这个函数值越大,文章阅读难度越小。其中: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.
这篇短文的 =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

下面是我开了四个哈希的代码。。。还是爆了两个。。orz

MY.CPP

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

const int kkk=3035691;
const int nod=2634527;

int cnt=0,num=0,jud[4][60],hash[4][kkk];
long long ans[10500];
bool flag;
char c;
int s[30];

long long p,q;
int main()
{
    //freopen("assess.out","w",stdout);

    std::ios::sync_with_stdio(false);
    std::cin.tie(0);

    while(scanf("%c",&c)!=EOF)
    {   
        if(c>='A'&&c<='Z')c-='A'-'a';
        if(c>='a'&&c<='z')
        {
            num++;
            jud[0][num] = (jud[0][num-1]*31+(c-'a'+1))%nod;
            jud[1][num] = (jud[1][num-1]*37+(c-'a'+1)*(c-'a'+1))%nod;
            jud[2][num] = (jud[2][num-1]*59+(c-'a'+1)*6)%nod;
            jud[3][num] = (jud[3][num-1]*79+(c-'a'+1)*(c-'a'+1))%nod;           
            flag = 1;           
        }
        else if(flag)
        {
            q++;
            if(((!hash[0][jud[0][num]]&&!hash[1][jud[1][num]])
            &&(!hash[2][jud[2][num]]&&!hash[3][jud[3][num]])))
            {
                cnt++;
                hash[0][jud[0][num]] = cnt;
                hash[1][jud[1][num]] = cnt;
                hash[2][jud[2][num]] = cnt;
                hash[3][jud[3][num]] = cnt;                         
                ans[cnt]++;
            }
            else
            {   
                ans[hash[0][jud[0][num]]]++;            
            }

            memset(jud,0,sizeof(jud));
            flag = 0;   num = 0;
        } 
    }

    for(int i=1;i<=cnt;i++)p += (long long)pow(ans[i],4);
    cout << p << " " << q;
    return 0;
}

等会回来搞。
下面是基于Trie的正解:

STD.CPP

#include<bits/stdc++.h>
using namespace std;
int tot,len,num,ans;
char s[55];
struct node{int cnt;int son[26];}tree[1005*50];
inline void inser()
{
    int po=0;
    for(int i=0;i<len;i++)
    {
        if(tree[po].son[s[i]-'a']==0)tree[po].son[s[i]-'a']=++tot;
        po=tree[po].son[s[i]-'a'];
    }
    tree[po].cnt++;
}
inline void circu()
{
    for(int i=1;i<=tot;i++)if(tree[i].cnt)
    ans+=(tree[i].cnt*tree[i].cnt*tree[i].cnt*tree[i].cnt);
}
int main()
{
    char ch;
    while(ch=getchar())
    {
        if(ch<0||ch>128)break;
        len=0;
        memset(s,0,sizeof(s));
        for(ch;(ch<'a'||ch>'z')&&(ch<'A'||ch>'Z');ch=getchar())if(ch<0||ch>128)break;
        for(ch;(ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z');ch=getchar())
        {
            if(ch<='Z')ch+=('z'-'Z');
            s[len++]=ch;
        }
        if(len){num++;inser();}
    }
    circu();
    cout<<ans<<" "<<num<<endl;
    return 0;
}

Route(100/100)

题目背景
SOURCE:NOIP2015-SHY-5

题目描述
一条直线上有 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] 个人(总人数)打招呼。

样例数据 1
输入  [复制]

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]

感觉就是小学奥数题怎么全班很多人都没做。。。
甚至还比一些大佬的代码短一点。。

MY/STD.CPP

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

const int kkk=1005;

int n;
struct node{
    int sx,sy;
    int tx,ty;
    int k,b;
    void add()
    {
        cin >> sy >> sx >> tx;
        if(tx-sx<0) k = -1;
        else    k = 1;
        ty = sy+k*(tx-sx);
        b = sy-sx*k;
    }   
}s[kkk];

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);

    cin >> n;
    for(int i=1;i<=n;i++)s[i].add();

    for(int i=1;i<=n;i++)
    {
        int ans=0;
        for(int j=1;j<=n;j++)
        if(i!=j)
        {
            if(s[i].k!=s[j].k)
            {
                double x,y;
                x = ((double)abs(s[i].b-s[j].b)/2);
                y = ((double)abs(s[i].b+s[j].b)/2);

                if(min(s[i].sx,s[i].tx)<=x)
                if(max(s[i].sx,s[i].tx)>=x)
                if(min(s[i].sy,s[i].ty)<=y)
                if(max(s[i].sy,s[i].ty)>=y)

                if(min(s[j].sx,s[j].tx)<=x)
                if(max(s[j].sx,s[j].tx)>=x)
                if(min(s[j].sy,s[j].ty)<=y)
                if(max(s[j].sy,s[j].ty)>=y) 
                    ans++;
            }else{
                if(s[i].b==s[j].b)

                if(max(s[i].sx,s[i].tx)>=min(s[j].sx,s[j].tx))
                if(max(s[j].sx,s[j].tx)>=min(s[i].sx,s[i].tx))
                    ans++;                              
            }
        }
        cout<<ans<<" ";
    }
    return 0;
}

Work(30/100)

题目背景
SOURCE:NOIP2015-SHY-5

题目描述
假设现在离 noip 还有 m 天,有 n 个人要去参加比赛。他们每个人都有一个预定的训练量 r[i] ,所以每一天他们都抓紧时间练习。但是由于条件限制,第 i 天只有 t[i] 的时间可以练习。

我们都知道,一个人在开始干活以前总要浪费一些时间做一些杂七杂八的事情。现在我们假定第 i 个人每天在训练前浪费的时间是固定的,记为 d[i] 。这段浪费掉的时间过后,选手会专心致志训练,他们会充分利用剩下的时间。然而一个可能的情况时,一个人还在无所事事的时候,某一天的训练时间已经过去了,所以他那一天什么事情都没有做。

现在请问每个人在第几天的时候可以完成自己的训练任务。当然会存在志向远大但是很懒惰的人到最后也是做不完的情况。

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

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

样例数据 1
输入  [复制]

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

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

暴力30%的代码:做了一个小时做不动了抬手就是一个暴力。(不过题上本来说的有40%的暴力分??)

MY.CPP

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

const int kkk=100050;

int d;
long long n,m,t[kkk],r;
long long s[kkk],g[kkk],sum[kkk];

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

    std::ios::sync_with_stdio(false);
    std::cin.tie(0);    

    cin >> n >> m;
    for(int i=1;i<=m;i++){cin>>t[i];s[t[i]]++;sum[i]=sum[i-1]+t[i];}

    for(int i=1;i<=kkk+2;i++){g[i]=g[i-1]+s[i-1]*(i-1);s[i-1]+=s[i-2];}

    for(int i=1;i<=n;i++)
    {
        cin >> d >> r;
        if(r>sum[m]-g[d]-(m-s[d])*d)cout<<0<<" ";
        else
        {
            int jud=0,j;
            for(j=1;j<=m;j++)
            {
                jud += t[j]-min(t[j],1ll*d);
                if(jud>=r)break;
            }
            cout<<j<<" ";
        }
    }
    return 0;
}

题解解决了我在做题时想到二分后一直不知道怎么求对于特定的一个人他能利用的时间的前缀和的问题:

把人的玩耍时间和每天的训练时间从多到少排序,用两个树状数组存大于这个人的玩耍时间的那一天在第几天,二分答案
二分答案我自己还不能而分出正解。。。要练。。。

STD.CPP

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

const int kkk=200050;

long long n,m,ans[kkk];

struct node1{int t,p;}t[kkk];
struct node2{int d,r,p;}s[kkk];

bool comp1(const node1 &a,const node1 &b){return a.t>b.t;};
bool comp2(const node2 &a,const node2 &b){return a.d>b.d;};

struct tree{
    int num[kkk];

    int lowbit(int k){return k&(-k);};

    void add(int k,int v){while(k<=m){num[k]+=v;k+=lowbit(k);}};//一定要是 <= m
    int sum(int k){int re=0;while(k>0){re+=num[k];k-=lowbit(k);}return re;};
    int getans(int i,int j){return sum(j)-sum(i-1);};
}getday,getsum;

bool check(int num,int i)
{
    int jud = getsum.getans(1,num)-getday.getans(1,num)*s[i].d;
    if(jud>=s[i].r)return true;
    else return false;
}

int half(int i)
{
    int l=1,r=m,mid;
    while(l<=r)
    {
        mid = (l+r)>>1;
        if(check(mid,i))r=mid-1;
        else l=mid+1;
    }
    if(l>m)return 0;
    return l;
}

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);    

    cin >> n >> m;
    for(int i=1;i<=m;i++){t[i].p=i;cin>>t[i].t;}
    for(int i=1;i<=n;i++){s[i].p=i;cin>>s[i].d>>s[i].r;}

    sort(t+1,t+m+1,comp1);  
    sort(s+1,s+n+1,comp2);  

    int cnt=0;
    for(int i=1;i<=n;i++)
    {
        while(t[cnt+1].t>s[i].d)
        {
            cnt++;
            getday.add(t[cnt].p,1);
            getsum.add(t[cnt].p,t[cnt].t);      
        }
        ans[s[i].p] = half(i);
    }
    for(int i=1;i<=n;i++)cout << ans[i] << " ";

    return 0;
}

感想

。。。。。。
平时多做些Dp,二分题,还有背模板(曾老要抽了)。。。
二分要分对,哈希要算对。。

番外

新领养了一堆细胞(话说截止今天18:36都7个小时了还不死。。。)

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值