[Contest Hunter #54]CH NOIP 2014 模拟赛day1被虐记

来源:互联网 发布:凡科互动游戏 源码 编辑:程序博客网 时间:2024/05/02 00:54

九月份

在noip吧看到了CH的NOIP模拟赛广告,于是我毫不犹豫地报名参加了


10.3. 下午

听说晚上的比赛会用NOI 2011的原题,瞬间吓尿。。。


18:30

比赛开始了,第一题一看就是DP,很快搞定

19:00

开始做第二题“兔农”!题目背景用的是NOI 2011的“兔农”原题,被吓尿了,吓昏一段时间后发现好像是个递推水题

19:20

做完第二题好开心,没事干带入一个大数据玩玩,发现十秒钟才出结果,吓昏

昏迷过后发现n最大是一亿,O(n)的递推只能拿到30分,跪了。。。

这个题只能用O(logn)以下复杂度的算法,否则会有70分TLE滚粗

用骗分导论上的方法,我把递推过程中的数字打个表找规律,发现递推过程中会出现循环节,好开心,也许把前十万的递推数据打个表,然后找规律便能在常数时间内找到答案呢!赶紧写一个常数复杂度的程序去~

21:00

写完了第二题的新方法,对拍检查无误,不做啦,第三题打表收场,出去玩咯~

22:00

出去玩回来,比赛结束了,发现我滚粗了,p1 90分,挂在了333这个点(我写程序检查数据不合法性时根本就没考虑到这个点),滚掉10分,p2 50分,因为数组开小了(只打前1W的表),如果开10W的表能拿70分,p3打表完美弄到5分。

最终结果145分,145*2就是290分,在HB弱省就是国一,不过我感觉很忧伤,因为我有30分的失误本不该丢掉。

下面是我瞎诌的解题报告

problem 1

http://ch.ezoj.tk/contest/CH%20Round%20%2354%20-%20Streaming%20%235%20(NOIP%E6%A8%A1%E6%8B%9F%E8%B5%9BDay1)/%E7%8F%A0

序列型动态规划,对2333这样的子序列的终点进行dp即可,注意输入的数字序列中会出现2和3以外的数字,而且可能只有2或只有3,另外子序列可以是顺时针数出来的,也可以是逆时针数出来的,所以一定要小心,稍不留神便会白白丢掉几十分

#include <iostream>#include <stdio.h>#include <string.h>#include <algorithm>#define MAXN 200200using namespace std;int f[MAXN]; //f[i]=以第i位数字结尾的最大233序列长度int s[MAXN];int n;char in[MAXN];int main(){    bool hasTwo=false;    scanf("%s",in+1);    n=strlen(in+1);    for(int i=1;i<=n;i++)    {        if(in[i]=='2') hasTwo=true;        s[i]=in[i]-'0';        s[i+n]=s[i];    }    if(!hasTwo) //这里加一个条件判断:输入数字串中没有2,直接输出无解    {        printf("TvT\n");        return 0;    }    for(int i=1;i<=2*n;i++)    {        if(s[i]==2) f[i]=1;        else if(s[i]==3&&(s[i-1]==2||s[i-1]==3)) f[i]=f[i-1]+1;        else f[i]=0;    }    int ans=0,x=1;    for(int i=1;i<=2*n;i++)        if(f[i]>ans)        {            ans=f[i];            x=i;        }    memset(f,0,sizeof(f));    for(int i=2*n;i>=1;i--)    {        if(s[i]==2) f[i]=1;        else if(s[i]==3&&(s[i+1]==2||s[i+1]==3)) f[i]=f[i+1]+1;        else f[i]=0;    }    for(int i=1;i<=2*n;i++)        if(f[i]>ans)        {            ans=f[i];            x=i;        }    if(ans==0)        printf("TvT\n");    else    {        printf("2");        for(int i=1;i<ans;i++)            printf("3");        printf("\n");    }    return 0;}

problem 2

http://ch.ezoj.tk/contest/CH%20Round%20%2354%20-%20Streaming%20%235%20(NOIP%E6%A8%A1%E6%8B%9F%E8%B5%9BDay1)/%E5%85%8D%E5%86%9C

虽然说题目描述几乎和NOI 2011的兔农完全相同,但是两个题解法截然不同,此题正解是快速幂,虽然说递推过程中会有减1的情况出现,但是根据网上神犇们的说法,繁殖过程中,死掉一只兔子后,就再也不会死兔子了(之后兔子们永远幸福),或者一只兔子都不会死(一开始兔子们都永远幸福),所以我们只需要判断是否会死兔子,以及在哪一天死兔子,以这一天为分界线分开快速幂即可。

如果打表找循环节的话,开数组很考验RP,虽然是常数复杂度,效果并没有快速幂的方法好

#include <iostream>#include <fstream>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <algorithm>#include <map>#define MAXN 100000using namespace std;typedef long long LL;LL n,k,p;/*int fastPow(int x,int pow){    long long int ans=1,base=x;    for(;pow;pow>>=1)    {        if(pow&1)            ans=ans*base%p;        base=base*base%p;    }    return ans;}*/LL fastPow(LL a,LL b){    if(b==0) return 1%p;    if(b==1) return a%p;    LL tmp=fastPow(a,b>>1);    tmp=tmp*tmp%p;    if(b&1) tmp=tmp*a%p;    return tmp;}LL check() //检查是否会死掉一只兔子,如果会,返回死掉这只兔子的那一天{    LL tmp=1%k;    for(LL i=0;i<k;i++)    {        tmp=tmp+tmp;        if(tmp>=k) tmp-=k;        if(tmp==1) return i; //返回的i是死掉兔子的那一天    }    return -1; //返回-1表明不需要死兔子}int main(){    scanf("%lld%lld%lld",&n,&k,&p);    LL day=check();    if(day==-1||n<day) printf("%lld\n",fastPow(2,n+1));    else    {        LL tmp=(fastPow(2,day+1)+p-1)%p;        tmp=tmp*fastPow(2,n-day)%p;        printf("%lld\n",tmp);    }    return 0;}







0 0
原创粉丝点击