【题目】
不知为何,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个人),考得很不好,得多训练训练思维了!!!