2016.8.25 NOIP2012 day1 解题报告

考试总结:

1.  显然第一道送分题,我差一点直接打表来对拍了,后来发现我们的pdf有问题不能复制,并且我没有YJQ大神那样足够的时间每道题都对拍,就只能试过样例就遁,(其实这种密码我玩过,密码学入门密码,当时好像叫凯撒密码233);对了,ASCII的掌握也很重要,我之前一直以为大写在小写后面啧。(之间漏掉过大于以后减的步骤,这种简单题还是做少了居然耗了30min,以后好好检查争取一次过);

2.  这道题我拿到的第一反应就是贪心,马上想了一个贪心规则但自己总觉得是错的,花了很长的时间举反例举不出来,后来和第三道题换着做都没做完快疯了,然后发现我无法证伪,但是它本来就是正确的啊…所以说以后要多从正面,特别是反证的方面思考问题;最后写出来以后输出不对,才发现是前面不包括自己,当时懵比因为那样的话我的方法就错了,然后突然发现两边都乘以一个lef就一样了,还是一种很巧妙的思维转化吧,然后得出了正确的算法,当然由于畏难我没有写高精度,后来发现其实很简单,就几行,所以不要畏难,熟练掌握模板(对了,还有个技巧是sort排序可以各种写cmp,对于排序的灵活性非常有用;

3.  本来打算用DP啊背包啊记忆啊什么的,所以还是基本概念掌握不清晰,很明显这些算法不能用;后来发现就求min1,min2的时间复杂度最高,然后一个快排就可以解决问题(当然,要写很多个if很麻烦),最后还是决定拿70分走,然后发现太难调了,临交卷还没调出来orz.)

4.  总的来说,这套题考得排名不错,但我认为不是很理想,第二题证伪的时间太长,没有把握好时间,没有想到反证,高精度没敢写,最后一道题没有先检查再调试,导致很多一眼看出来的错调了很久,要站在逻辑的高度上。代码实现能力有待提高,60多行的程序应该写得心平气和思路清晰才对;第二三题都还是很有价值(第二题的证明,第三题的错orz);

解题报告:

一.   Vigenère密码

1.题意:通过按位的方式把暗文按照密钥翻译成明文,每个明文和密钥对应一个暗文;数据范围:密钥100,暗文1000;

2.注意:

1).是把暗文翻译成明文,害得我总觉得样例有问题,一定要仔细读题;

2).题目要求明文大写暗文保持大写,密钥大小写无关紧要;

3.分析:这道题的第二个注意揭示了,这是一道需要很多个if的题,只要考虑清楚,这道题就没问题;思路就是用ASCII码的运算,把密钥当做加法,a加0,b加1…

4..代码:

#include<iostream>

#include<cstdio>

#include<cstring>

using namespace std;

int lena,lenb;

char a[105],b[1005];//meaning

int main()

{

freopen("vigenere.in","r",stdin);

freopen("vigenere.out","w",stdout);

scanf("%s",a);getchar();scanf("%s",b);lena=strlen(a);lenb=strlen(b);

for(int i=0;i<lenb;i++){

int tmp=b[i];tmp-=a[i%lena];if(a[i%lena]<=‘Z‘)tmp+=‘A‘;else tmp+=‘a‘;

if(b[i]<=‘Z‘&&tmp<‘A‘)tmp+=26;//ditails;

else  if(b[i]>‘Z‘&&tmp<‘a‘)tmp+=26;

b[i]=tmp;

}

printf("%s",b);

return 0;

}//对了,用scanf一定记得注意换行符;

二.   国王游戏

  1. 题意:给定一个第一位不能动的数列,后面的得分为之前所有的左元素的乘积除以自己的右元素,使最大得分最小;

数据范围:对于20%的数据,有1≤n≤10,0 < a、b <8;

对于40%的数据,有1≤n≤20,0 < a、b < 8;

对于60%的数据,有1≤n≤100;

对于60%的数据,保证答案不超过109;

对于100%的数据,有1 ≤n ≤1,000,0 < a、b < 10000。

  1. 注意:

1)      是前面的所有人,不包括自己!

2)      <=10000的 1000次方应该是最多4000位,但如果是五位数就是5000了;

  1. 分析:要最大最小就对r*l从小到大排序,然后直接运算就行了;

算法证明:

1).基本思路:r*=l之后,本题就可以看作最左边包括自己的积除以r*l,左边的乘积一定是单增的,则除数也要单增,且单独看最后一个,被除数肯定是最大的,那么除数也要尽量大;

2)正确性证明:当时决定采用这个算法时已经没有时间了,其实即使不r*=l左边也是单增,但是r*=l和直接排r肯定是不一样的,所以这里还涉及到反证的思想;

①.不相等时:不相等时,前后交换,后面的那个数和之前在后面的那个数面对的被除数是一样的,也就是说当后面的元素确定后交换不影响后一个位置的除数,然后被除数一样,交换后除数反而小了,所以得到的数肯定比之前相同除数被除数小的情况大,也比之前相同被除数除数大的情况大,最大值即使不会变大,也不可能变小;

②。相等时:永远要记住讨论相等,交换后,后一个数除数没变被除数没变,把l大的放在后面的话,前面的数被除数小了除数没变,至少不会更大,但是前面被除数至少不会更大,除数又相等,所以至少不会让最大值变化(因为后一个要么相等要么更大),所以相等时可以随意;

(啊证明这种东西感觉对自己的逻辑学很有帮助);

4.  代码:#include<iostream>

#include<cstdio>

#include<algorithm>

#include<cstring>

using namespace std;

int maxn[5005],n,tmp[5005],ans[5005];

struct per

{

int l,r;

}a[1005];//条件

bool cmp(per x,per y)

{

if(x.r*x.l<y.r*y.l)return true;

return false;

}

void chengf(int u)

{

memset(tmp,0,sizeof(tmp));//高乘单!

for(int i=1;i<=5003;i++){

tmp[i]+=maxn[i]*a[u].l;tmp[i+1]+=tmp[i]/10;tmp[i]%=10;

}

for(int i=1;i<=5004;i++)maxn[i]=tmp[i];

}

void chuf(int u)

{

memset(tmp,0,sizeof(tmp));int flg=0,cnt=0;

for(int i=5004;i>=1;i--){

tmp[i]=(cnt*10+maxn[i])/a[u].r;

cnt=(cnt*10+maxn[i])%a[u].r;

}

for(int i=5004;i>=1;i--)if(tmp[i]>ans[i]){flg=1;break;}

if(flg)for(int i=5004;i>=1;i--)ans[i]=tmp[i];

}

int main()

{

freopen("game.in","r",stdin);

freopen("game.out","w",stdout);

scanf("%d",&n);

for(int i=1;i<=n+1;i++)scanf("%d %d",&a[i].l,&a[i].r);

sort(a+2,a+n+2,cmp);maxn[1]=a[1].l;

for(int i=2;i<=n+1;i++){

chuf(i);

chengf(i);

}

int tail=4004;while(!ans[tail])tail--;//虽然不用改,但没改完太好笑了

for(int i=tail;i>=1;i--)printf("%d",ans[i]);

return 0;

}

三.   开车旅行

1.题意:A先开,去第二小的,B开去第一小的,AB轮流,不能到或者取不到停止,求给定x,A,B开的距离比值最小的sta以及给定sta,x(能开的距离),AB开的距离;

数据范围:对于30%的数据,有1≤N≤20,1≤M≤20;

对于40%的数据,有1≤N≤100,1≤M≤100;

对于50%的数据,有1≤N≤100,1≤M≤1,000;

对于70%的数据,有1≤N≤1,000,1≤M≤10,000;

对于100%的数据,有1≤N≤100,000,1≤M≤10,000,-1,000,000,000≤Hi≤1,000,000,000,0≤X0≤1,000,000,000,1≤Si≤N,0≤Xi≤1,000,000,000,数据保证Hi互不相同。

2.注意:

1).距离为海拔高度差,距离相同,海拔低的近;

2)对于第一问,比值相同输出海拔高的;

3.模拟70分,先读取时遍历前面求min1,min2的值和端点(也可以只存端点),然后像链表一样走就行了,这道题正解是集合(或者用双向链表且走完删除也可以)+倍增(其实确定状态(包括谁开)以后就是唯一路径的树了),还没写;

4.代码:

(70)

#include<iostream>

#include<cstdio>

#include<cmath>

#include<cstring>

using  namespace std;

int n,a[100005],min1[100005][2],min2[100005][2],x,maxn,m,sta;

int main()

{

freopen("drive.in","r",stdin);

freopen("drive.out","w",stdout);

memset(min1,127,sizeof(min1));memset(min2,127,sizeof(min2));

scanf("%d",&n);for(int i=1;i<=n;i++){

scanf("%d",&a[i]);for(int j=1;j<i;j++){

int tmp= abs(a[i]-a[j]);

if(tmp<min1[j][0]||(tmp==min1[j][0]&&a[i]<a[j])){

min2[j][1]=min1[j][1];min2[j][0]=min1[j][0];

min1[j][0]=tmp;min1[j][1]=i;}

else if(tmp<min2[j][0]||(tmp==min2[j][0]&&a[i]<a[j])){

min2[j][0]=tmp;min2[j][1]=i;}

}}

scanf("%d",&x);long long maxna=1,maxnb=0;//不能被覆盖;

for(int i=1;i<=n;i++){//边界处理;

long long flg=i,cnt=0,ansa=0,ansb=0;

while(flg<=2e9&&flg!=n){

if(!cnt){

if(ansa+ansb+min2[flg][0]>x)break;

ansa+=(long long)min2[flg][0];

flg=min2[flg][1];

cnt=1;

}

else{

if(ansa+ansb+min1[flg][0]>x)break;

ansb+=(long long)min1[flg][0];

flg=min1[flg][1];

cnt=0;

}

}

if(maxnb==0&&a[maxn]<a[i]){

maxna=ansa;maxnb=ansb;maxn=i;}//特殊情况处理//周全;

else if(ansb&&((double)maxna/maxnb>(double)ansa/ansb||((double)ansb*maxna==(double)maxnb*ansa&&a[maxn]<a[i]))){

maxna=ansa;maxnb=ansb;maxn=i;

}

}

printf("%d",maxn);

scanf("%d",&m);

for(int i=1;i<=m;i++)

{

scanf("%d %d",&sta,&x);

long long flg=sta,cnt=0,ansa=0,ansb=0;//该改的还是要记得改啊;

while(flg<=2e9&&flg!=n){

if(!cnt){

if((long long)ansa+ansb+min2[flg][0]>(long long)x)break;

ansa+=(long long)min2[flg][0];

flg=min2[flg][1];cnt=1;

}

else{

if((long long)ansa+ansb+min1[flg][0]>(long long)x)break;

ansb+=(long long)min1[flg][0];

flg=min1[flg][1];cnt=0;

}

}

printf("\n%I64d %I64d",ansa,ansb);//输出变量;

}

return 0;

}

时间: 2024-10-19 12:04:22

2016.8.25 NOIP2012 day1 解题报告的相关文章

NOIp 2013 Day1 解题报告

NOIp 2013 Day1 解题报告 1.   转圈游戏 不难看出答案就是(x+m*10k) mod n 用快速幂算法,复杂度O(log2k) 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 8 //variable// 9 int n,m,x,

暑训day1解题报告

A - Painting the sticks 因为不能覆盖涂/涂两次,所以就数数有几个三个一块儿就行了. #include<cstdio> int a[100],ans ; int main() { int n , t = 0 ; while (scanf("%d",&n)!=EOF) { for (int i=1; i<=n; ++i) scanf("%d",a+i); ans = 0 ; for (int i=1; i<=n ;

常州培训 day1 解题报告

第一题: 题目大意:给出一个字符串,找出满足条件A的区间的个数.A:字符A,B,C的出现次数相同. 都出现0次也算,区间的长度可以是0(就是只有一个数).30% |S| ≤ 100 .70% |S| ≤ 1000 .100% 1 ≤ |S| ≤ 1000000 . 解题过程: 1.考场上想不出AC算法,但是70分是很好拿的,最先想到先求出A,B,C出现次数的前缀和,枚举区间的两个端点,O(1)时间判断,枚举O(n^2). 2.一看后面的题目都不是很好写,就先来优化一下这题,由于只有A,B,C是有

CH Round #54 - Streaming #5 (NOIP模拟赛Day1)解题报告

最近参加了很多CH上的比赛呢~Rating--了..题目各种跪烂.各种膜拜大神OTZZZ T1珠 描述 萌蛋有n颗珠子,每一颗珠子都写有一个数字.萌蛋把它们用线串成了环.我们称一个数字串是有趣的,当且仅当它的第1位是2,且除了第1位以外的每一位都是3.例如,2,233,2333333都是有趣的数字串.现在,你可以从这串珠子的任意一颗开始读,沿着顺时针或逆时针方向,到任意一颗珠子停止.这样,你就可以读出一个数字串来.萌蛋想知道,所有能读出的有趣的数字串当中,最长的是哪一个数字串.当然,你也可能读不

2017.7.15清北夏令营精英班Day1解题报告

成绩: 预计分数:20+10+40 实际分数:100+10+40. 一百三十多人的比赛全场rand7还水了个鼠标+键盘 unbelievable! 考试题目链接: https://www.luogu.org/team/show?teamid=1353 T1 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm&

NOIp 2011 Day1 解题报告

1.    铺地毯 送分题…… 枚举给定矩形,判定给定点是否在矩形内.求出标号最大的哪个矩形即可. 复杂度O(N) 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 8 //variable// 9 int n,a[10010],b[10010],g

2016/9/25编写java实验报告时对synchronized(同步代码块)的一些感悟

通过此次实验,明白了多线程的设置和启动.synchronized代码块的用法.线程的优先级使用方法.知道了那几类资源是线程共享的. 我现在理解的多线程是:实例化一个继承了Thread类或实现了Runnable接口的类(继承是为了使其拥有参与多线程的资格):然后再将该类run()中的代码交由Thread类来执行,以此实现多线程的同步运行 经过翻阅网络博客,和代码尝试,进一步的认识了同步代码块: ①synchronized(){}代码块在执行时先判断括号里的对象有没有被上锁: 若无,则上锁并开始执行

CDOJ 25 点球大战(penalty) 解题报告

简单的字符串处理 坑点,有人可能没名字(名字为空) 有人名字可能为blablablano 但是因为输入保证最后五个字符为 good(前面有个空格) 因为如果输入意思是no good的话,no前面必须有一个空格 所以只需要判断倒数第6.7.8个字符是不是' '.'n'.'o'就可以了 当然,如果出现名字为空,结果为good,字符串长度达不到8,要判断一下字符串的长度 以上解决之后稍微关注一下输出格式就可以了 #include <cstdio> #include <cstring> u

8.24-8.25联赛模拟 解题报告

T1: 直接模拟,然后坐标相同的点的统计用sort来去重,用map等STL会TLE... // MADE BY QT666 #include<cstdio> #include<algorithm> #include<cmath> #include<iostream> #include<cstring> using namespace std; typedef long long ll; const int N=2000050; struct da