九月份
在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
序列型动态规划,对2333这样的子序列的终点进行dp即可,注意输入的数字序列中会出现2和3以外的数字,而且可能只有2或只有3,另外子序列可以是顺时针数出来的,也可以是逆时针数出来的,所以一定要小心,稍不留神便会白白丢掉几十分
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define MAXN 200200
using 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
虽然说题目描述几乎和NOI 2011的兔农完全相同,但是两个题解法截然不同,此题正解是快速幂,虽然说递推过程中会有减1的情况出现,但是根据网上神犇们的说法,繁殖过程中,死掉一只兔子后,就再也不会死兔子了(之后兔子们永远幸福),或者一只兔子都不会死(一开始兔子们都永远幸福),所以我们只需要判断是否会死兔子,以及在哪一天死兔子,以这一天为分界线分开快速幂即可。
如果打表找循环节的话,开数组很考验RP,虽然是常数复杂度,效果并没有快速幂的方法好
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <map>
#define MAXN 100000
using 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;
}