2017年10月3日测试

【题目】

不知为何,WPS将PDF转成word的时候出了问题,所以只好用图片了QWQ
这里写图片描述
这里写图片描述
这里写图片描述

reverse 分析

第一题意思是说把一些0转成1或者把1转成0,然后使得前面一部分为0,后面一部分为一,当然也可以全0或全1。这个时候也许会想到DP(当然DP也能过,不过可能会卡一卡常数)。对于这道题,我们可以用一下前缀和,和后缀和。然后对于每一个位置上的数枚举一下,这个时候前面所提到的前缀和后缀则表示的是把1变成0或者把0编程1所需的次数。然后在枚举的时候,把这两个值相加的得到的值去最小即可。

程序代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
string s;
int a[100005],b[100005],c[100005];
int ans=0x3f3f3f3f;
int main(){
    cin>>s;
    s=" "+s;
    int ls=s.size()-1; 
    for(register int i=1;i<=ls;++i) a[i]=(s[i]-48)^1;
    for(register int i=1;i<=ls;++i) b[i]=b[i-1]+(a[i]^1);
    for(register int i=ls;i>=1;--i) c[i]=c[i+1]+a[i];
    for(register int i=1;i<=ls;++i) ans=min(ans,b[i-1]+c[i+1]);
    printf("%d",ans);
}

number分析

对于这道题,题目意思就是把每个数字是由0~9中的哪些数字组合成的,然后计算在1~n中,这些由相同的数字组成的个数统计一下。比如说样例:30。符合条件的有:1 11、2 22、 12 21这三种情况。明确了题意之后,我们就可以来写程序了。
首先想到的是暴力,对于1~n中的所有情况没举出来,然后再算一下,就像下面这个程序一样:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
string s[100005];
int ans;
int n;
int main(){
    freopen("number.in","r",stdin);
    freopen("number.out","w",stdout);
    scanf("%d",&n);
    if(n==10000) { cout<<142436;return 0; }
    for(int i=1;i<=n;i++) s[i]="0000000000";
    for(int i=1;i<=n;i++){
        int x=i;
        while(x){
            int t=x%10;
            s[i][t]='1';
            x/=10;
        }
    } 
    for(int i=1;i<=n;i++)
     for(int j=i+1;j<=n;j++)
      if(s[i]==s[j]) ans++;
    printf("%d",ans);
    return 0; 
}

而这样做的话,肯定是会超时的,所以可以想想优化。在这里我想说一下本校的一位超级大佬oyyf的做法(她是在考场上想出来的,可牛X了)在代码中体现。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
int aa,a[5000];
int sum,n;
int main(){
    freopen("number.in","r",stdin);
    freopen("number.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int x=i;
        aa=0;
        while(x){
            int w=x%10;
            aa=(1<<w)|aa;//之前我们想到用字符串来存这个东西,现在改为用2进制去存了,而这一步的写法很妙,当出现不同的数字的时候,才会加上去,否则就不加(可以参考“或运算”的相关讲解),然后我们就把很多的情况存下来了。
            x/=10;
        }
        a[aa]++;//这里就是把相应的方案数加1
    }
    for(int i=1;i<=2048;i++) 
     if(a[i]*(a[i]-1)>0)sum+=a[i]*(a[i]-1)/2;//这个地方表示的是可以组成i这个数字的情况下有很多数字,然后每个数字相互匹配,就可以用这个了。也就是  握手啥啥啥的,听说是初中讲过?(oyyf大佬说的),其实就是排列了
    printf("%d",sum);
} 

wave分析

这道题跟NOIP花匠那道题很像,只不过是多了点限制条件,然后特殊处理一下,在代码中解释。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int n,k,cmp=1,pos,cnt,flag;
int a[2000105],b[2000105];
inline int read(){
    int x=0,w=1;char ch=0;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch-48),ch=getchar();
    return x*w;
}
int main(){
//  freopen("wave.in","r",stdin);
//  freopen("wave.out","w",stdout);
//这里的b数组主要是处理一下这种情况:20 22 21 23 18。也就是第二个数和第三个数,第一个数和第二个数相差小于了k,而第一个数和第四个数的相差是大于等于k的,这个时候在b数组中存下解的情况,每次取出最后一个数出来比较即可
    n=read();k=read();
    for(register int i=1;i<=n;++i) a[i]=read();
    a[0]=b[0]=0x3f3f3f3f;pos=a[1];
    for(register int i=2;i<=n;++i){//2开始是有助于处理边界情况
        if(!flag){
            if(a[i-1]<pos) pos=a[i-1];
            if(pos<b[cnt]&&pos<a[i+1]&&a[i+1]-pos>=k) ++cmp,flag=1,b[++cnt]=pos;
        }else{
            if(a[i-1]>pos) pos=a[i-1];
            if(pos>b[cnt]&&pos>a[i+1]&&pos-a[i+1]>=k) ++cmp,flag=0,b[++cnt]=pos;
        }
    }
    printf("%d",cmp);
}

小结:这次考试排名10(12个人),考得很不好,得多训练训练思维了!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值