T1 reverse
题目描述
0比1小,所以一个串中如果0全在1前面,这个串就比较和谐。对于一个只包含0和1的串,你每次可以将一个0变成1,或者将一个1变成0。那么,最少需要变多少次才能把保证所有的0在1前面呢?
输入输出格式
输入格式:
一个01串
输出格式:
一个数即答案
输入输出样例
输入样例#1:
010001
输出样例#1:
1
说明
对于40%的数据,len<=20
对于70%的数据,len<=1000
对于100%的数据,len<=10^5
题解:
我好像理解错题目了,我以为必须有1和0,好像只有1或者只有0也可以。
枚举1的数量
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 100009
#define inf 1000090
using namespace std;
char s[maxn];
int len,cnt,tmp,p,now,ans;
int main(){
freopen("reverse.in","r",stdin);
freopen("reverse.out","w",stdout);
scanf("%s",s+1);len=strlen(s+1);
for(int i=1;i<=len;i++)
if(s[i]=='1')cnt++;
if(cnt==0||cnt==len){
cout<<"0
";
return 0;
}
ans=inf;
for(int i=1;i<len;i++){
tmp=cnt;p=i;now=0;
for(register int j=len;j>=1;j--){
if(s[j]=='1')tmp--,p--;
else p--,now++;
if(!p){
ans=min(ans,now+tmp);break;
}
if(len>=1009&&i>=100){
printf("%d
",ans);
return 0;
fclose(stdin);fclose(stdout);
}
}
}
printf("%d
",ans);
fclose(stdin);fclose(stdout);
return 0;
}
统计‘1’的前缀和,枚举01分界点,取min
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 100008
#define inf 1000000000
using namespace std;
char s[maxn];
int ans,len,sum[maxn];
int main(){
scanf("%s",s+1);len=strlen(s+1);ans=inf;
for(int i=1;i<=len;i++)sum[i]=sum[i-1]+(s[i]=='1');
for(int i=0;i<=len;i++)ans=min(ans,sum[i]+(len-i)-(sum[len]-sum[i]));
printf("%d
",ans);
return 0;
}
看到同学写的dp
dp[i][0]是第i位是0的最小改变次数,dp[i][1]是第i位是1的最小改变次数。
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 100009
using namespace std;
char s[maxn];
int len,dp[maxn][2];
int main(){
scanf("%s",s+1);len=strlen(s+1);
for(int i=1;i<=len;i++){
if(s[i]=='0'){
dp[i][1]=min(dp[i-1][0]+1,dp[i-1][1]+1);
dp[i][0]=dp[i-1][0];
}else{
dp[i][1]=min(dp[i-1][0],dp[i-1][1]);
dp[i][0]=dp[i-1][0]+1;
}
}
printf("%d
",min(dp[len][1],dp[len][0]));
return 0;
}
T2 Number
题目描述
给定n,求有多少对<x,y>满足:
x,y∈[1,n],x<y
x,y中出现的[0,9]的数码种类相同
输入输出格式
输入格式:
一个整数n
输出格式:
输出一个数即答案
输入输出样例
输入样例#1:
30
输出样例#1:
30暴力
AC
20
AC
3
题解:O(n^2)
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int ans,n,vis[11],Vis[11]; inline int read(){ char ch=getchar();int x=0,f=1; for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0'; return x*f; } bool ok(int x,int y){ memset(vis,0,sizeof(vis)); memset(Vis,0,sizeof(Vis)); int cnt=0,js=0; while(x){ if(vis[x%10]==0){ vis[x%10]=true; cnt++; } x/=10; } while(y){ if(vis[y%10]==0)return false; if(Vis[y%10]==0){ js++;Vis[y%10]=true; } y/=10; } return cnt==js; } int main(){ n=read(); for(int i=1;i<=n;i++){ for(int j=i+1;j<=n;j++){ if(ok(i,j))ans++; } } printf("%d ",ans); return 0; }
for循环,分别计算小于i,且与i数码相同的数的个数。
当i时,分解i。用二进制串表示那些数出现过,如0000000011,表示0和1出现过。
那么么v[0000000011]++;表示只有0和1的数的个数+1
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,v[2000]; long long ans; void read(int &x){ char ch=getchar();x=0;int f=1; for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0'; x*=f;return; } int main(){ read(n); for(int i=1;i<=n;i++){ int now=0,a=i; while(a){ int k=a%10; now|=1<<k; a/=10; } ans+=v[now]++; } printf("%lld ",ans); return 0; }
ps:读入优化要换风格了...之前的竟然慢好多..还是用取地址的吧...不太习惯.
T3 Wave
题目描述
给定一个长为n的数列,试求一个最长的不稳定波动子序列满足任意偶数项的值不小于其相邻两项的值,且相邻两项的差不小于k。
输入输出格式
输入格式:
输入第一行两个正整数n,k。
第二行n个非负整数描述这个数列。
输出格式:
输出一个整数即为答案。
输入输出样例
输入样例#1:
10 3
2 6 7 9 0 3 7 6 4 4
输出样例#1:
5
说明
对于20%的数据,n<=10^3
对于70%的数据,n<=10^5
对于100%的数据,n<=2*10^5,数列中的数不超过2^31-1
题解:
dp,O(n^2).dp[i][1]表示所选择的是偶数项,dp[i][0]表示选择的是奇数项。
#include<iostream> #include<cstdio> #include<cstring> #define maxn 1000009 #define inf 2147483647 using namespace std; int ans,n,k,w[maxn],dp[maxn][3]; inline int read(){ char ch=getchar();int x=0,f=1; for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0'; return x*f; } int main(){ n=read();k=read(); for(int i=1;i<=n;i++)w[i]=read(); for(int i=1;i<=n;i++)dp[i][0]=dp[i][1]=1; for(int i=1;i<=n;i++){ for(register int j=1;j<i;j++){ if(w[j]-w[i]>=k&&((dp[j][1]+1)&1)) dp[i][0]=max(dp[i][0],dp[j][1]+1); if(w[i]-w[j]>=k&&(((dp[j][1]+1)&1)==0)) dp[i][1]=max(dp[i][1],dp[j][0]+1); } ans=max(ans,max(dp[i][1],dp[i][0])); } printf("%d ",ans); return 0; }
正解:贪心 在满足k的限制下,偶数项尽量大 奇数项尽量小
#include<iostream> #include<cstdio> #include<cstring> #define maxn 2000009 using namespace std; int n,k,m,ans,cur; int a[maxn]; void read(int &x){ char ch=getchar();x=0;int f=1; for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0'; x*=f; } int main(){ read(n);read(k); for(int i=0;i<n;i++)read(a[i]); ans=1;m=0;cur=a[0]; for(int i=1;i<n;i++){ if(m){ if(cur-a[i]>=k) m=0,ans++,cur=a[i]; else cur=max(cur,a[i]); }else{ if(a[i]-cur>=k) m=1,ans++,cur=a[i]; else cur=min(cur,a[i]); } } printf("%d ",ans); return 0; }