18708 最大子段和
时间限制:1000MS 代码长度限制:10KB
提交次数:0 通过次数:0
题型: 编程题 语言: 不限定
Description
一个整数序列,选出其中连续且非空的一段使得这段和最大。
输入格式
第一行是一个正整数N,表示了序列的长度(0=<N<=200000)。
第二行包含N个绝对值不大于10000的整数ai。
输出格式
一个整数,为最大的子段和。子段的最小长度为1。数据确保结果在类型int范围内。
输入样例
7
2 -4 3 -1 2 -4 3
输出样例
4
提示
【样例说明】
2,-4,3,-1,2,-4,3中,最大的子段和为4,该子段为第三元素至第五元素,即3,-1,2。
题解:典型的动态规划或者分治。
分治法(难)
#include<iostream>
#include<cstdio>
using namespace std;
int num[200010];
int f(int left,int right)
{
//printf("%d %d\n",left,right);
if(right==left+1)
{
return max(num[left],max(num[right],num[left]+num[right]));
}
else if(left==right)
{
return num[left];
}
//过中点
int mid=(left+right)/2;
int mmax=num[mid],temp=num[mid];
//从中点向左延伸,寻找连续子序列最大值
for(int i=mid-1;i>=left;i--)
{
temp+=num[i];
mmax=max(mmax,temp);
}
temp=mmax;
for(int i=mid+1;i<=right;i++)
{
temp+=num[i];
mmax=max(mmax,temp);
}
int mmax1=f(left,mid-1);//注意是mid-1即不过中点
int mmax2=f(mid+1,right);
//printf("%d %d %d\n",mmax1,mmax2,mmax);
//printf("*%d %d\n",left,right);
return max(max(mmax1,mmax2),mmax);
}
int main ()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&num[i]);
}
long long mmax=f(1,n);
cout<<mmax<<endl;
return 0;
}
动态规划法
#include<iostream>
#include<cstdio>
using namespace std;
long long dp[200010];
int num[200010];
int main ()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&num[i]);
}
long long mmax=-20000;
for(int i=1;i<=n;i++)
{
if(dp[i-1]>0)
{
dp[i]=num[i]+dp[i-1];
}
else dp[i]=num[i];
if(dp[i]>mmax)
{
mmax=dp[i];
}
}
cout<<mmax<<endl;
return 0;
}
18709 魔法
时间限制:1000MS 代码长度限制:10KB
提交次数:0 通过次数:0
题型: 编程题 语言: 不限定
Description
农夫约翰的奶牛场有很多奶牛,奶牛有黑白两种颜色。现在奶牛们排成整齐的一列去参加镇上的游行活动。
约翰希望白色奶牛都排在前面,黑色的奶牛都排在后面。但现在队列中奶牛的颜色是混乱的,并且奶牛们都不愿意改变位置。
幸运的是,约翰有一根魔法棒,每挥舞一次魔法棒就可以改变一头奶牛的颜色。
请问,约翰至少要挥舞多少次魔法棒,才能将队列改成他希望的状态。注意,可以将所有的奶牛都变成白色,或者都变成黑色。
输入格式
第一行一个正整数n,表示奶牛的头数。(1<=n<=200000)。
第二行n个正整数,均为1或2,1表示白色奶牛,2表示黑色奶牛。
输出格式
一个正整数,表示挥舞魔法棒的最少次数。
输入样例
7
2 2 1 1 1 2 1
输出样例
3
提示
可以把1和2号奶牛变成1,7号奶牛变成2,或者全部奶牛变成1,最少需要3次。
题解:我们可以o(n)枚举白牛与黑牛的交界处,这N种情况的最值就是答案啦。那枚举完,假设第一头黑牛的位置是pos,我们用sum黑表示黑牛前n项和,sum白表示白牛。那么就有变化次数就是=sum黑[pos-1]+sum白[n]-sum[pos-1]。
#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;
int sum[200010][2];//0表示白,1表示黑
int main ()
{
int n;
scanf("%d",&n);
int num;
for(int i=1;i<=n;i++)
{
scanf("%d",&num);
sum[i][0]=sum[i-1][0];
sum[i][1]=sum[i-1][1];
if(num==1)
{
sum[i][0]=sum[i-1][0]+1;
}
else
{
sum[i][1]=sum[i-1][1]+1;
}
}
int mmax=1000000;
for(int i=1;i<=n;i++)
{
int temp1=sum[i][1]-sum[i][0]+sum[n][0];
mmax=min(temp1,mmax);
}
printf("%d\n",mmax);
return 0;
}
18711 字符串去重
时间限制:1000MS 代码长度限制:10KB
提交次数:0 通过次数:0
题型: 编程题 语言: 不限定
Description
一个完全由小写字母组成的长度为n的字符串,现在要求你去除所有重复的字母,并将剩下的字母按从小到大的次序输出。
如输入baaadccaab,输出abcd。
输入格式
第一行一个整数n,表示字符串长度(0<=n<=100000)。
第二行一个字符串。
输出格式
去除所有重复的字母,并将剩下的字母按从小到大的次序输出。
输入样例
10
baaadccaab
输出样例
abcd
题解:直接对出现的字符进行标记就可以了
#include<iostream>
#include<cmath>
#include<cstdio>
#include<set>
#include<string>
#include<cstring>
using namespace std;
char s[100010];
int book[27];
int main ()
{
int n;
scanf("%d",&n);
getchar();
gets(s);
for(int i=0;i<n;i++)
{
book[s[i]-96]=1;
}
for(int i=1;i<=26;i++)
{
if(book[i])
printf("%c",96+i);
}
return 0;
}
18710 统计不同数字的个数(升级版)
时间限制:1000MS 代码长度限制:10KB
提交次数:0 通过次数:0
题型: 编程题 语言: 不限定
Description
由键盘输入n个整数,统计不同数字的个数(0<=n<=200000)。
PS:此题目和1040仅数据规模不同。但如果使用如下O(n2)级别的算法必然会超时。
int main()
{
int a[21],i,c=0,b,j;
for(i=1;i<=20;i++)
{
cin>>b;
for(j=1;j<=c;j++)
{
if(b==a[j])
{
break;
}
}
if(j>c)
{
a[c+1]=b;
c++;
}
}
cout<<c;
return 0;
}
输入格式
第一行一个整数n(0<=n<=200000)。
第二行n个整数a1,a2…an,(0<=ai<=200000)。
输出格式
仅一行,不同数字的个数。
输入样例
70 5 14 22 19 2 99 67 13 66 5 93 44 38 22 11 39 22 33 11
输出样例
16
题解:因为整数范围很小,直接开一个200000的数组对出现的数字标记
#include<iostream>
#include<cmath>
#include<cstdio>
#include<set>
#include<string>
#include<cstring>
using namespace std;
int book[200010];
int main ()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int num;
scanf("%d",&num);
book[num]=1;
}
int ans=0;
for(int i=0;i<=200000;i++)
{
if(book[i])
{
ans++;
}
}
cout<<ans<<endl;
return 0;
}
18063 圈中的游戏
时间限制:1000MS 代码长度限制:10KB
提交次数:0 通过次数:0
题型: 编程题 语言: G++;GCC;VC
Description
有n个人围成一圈,从第1个人开始报数1、2、3,每报到3的人退出圈子。编程使用链表找出最后留下的人。
输入格式
输入一个数n,1000000>=n>0
输出格式
输出最后留下的人的编号
输入样例
3
输出样例
2
题解:直接数组来模拟
#include<iostream>
#include<cmath>
#include<cstdio>
#include<set>
#include<string>
#include<cstring>
using namespace std;
int book[200010];
int main ()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int num;
scanf("%d",&num);
book[num]=1;
}
int ans=0;
for(int i=0;i<=200000;i++)
{
if(book[i])
{
ans++;
}
}
cout<<ans<<endl;
return 0;
}
18712 组合问题
时间限制:1000MS 代码长度限制:10KB
提交次数:0 通过次数:0
题型: 编程题 语言: 不限定
Description
找出从自然数1、2、……、m中任取k个数的所有组合,组合中字典序大的先输出。
例如m=5,k=3,应输出
5 4 3
5 4 2
5 4 1
5 3 2
5 3 1
5 2 1
4 3 2
4 2 1
3 2 1
输入格式
两个整数m和k,(1<=k<=m<=10)
输出格式
按字典序输出所有组合
输入样例
5 2
输出样例
5 4
5 3
5 2
5 1
4 3
4 2
4 1
3 2
3 1
2 1
题解:dfs进入一次回溯时,前面已经出现的数字标记,然后按顺序找到没标记的数字就可以了
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<stack>
using namespace std;
int book[12];
int box[12];
int n,k;
void dfs(int step)
{
if(step==k+1)
{
for(int i=1;i<=k;i++)
{
printf("%d ",box[i]);
}
printf("\n");
return;
}
for(int i=n;i>=1;i--)
{
if(!book[i]&&i<box[step-1])
{
box[step]=i;
book[i]=1;
dfs(step+1);
book[i]=0;
}
}
return;
}
int main ()
{
scanf("%d%d",&n,&k);
box[0]=n+1;
dfs(1);
return 0;
}
18713 整数的分解
时间限制:1000MS 代码长度限制:10KB
提交次数:0 通过次数:0
题型: 编程题 语言: 不限定
Description
输出一个正整数n的分解形式。例如,当n=4时,输出:
4=4
4=3+1
4=2+2
4=2+1+1
4=1+1+1+1
共计 5 种形式。
当n=7时,共有15种形式。
当n=10时,共有42种形式。
输入格式
一个整数n(1<=n<=10)。
输出格式
n的全部分解形式,注意分解式中数字值大的排在前面,如第一个数字值相同,那么比较第二个数字。
输入样例
4
输出样例
4=4
4=3+1
4=2+2
4=2+1+1
4=1+1+1+1
题解:很明显又是一次dfs的题,把每个等式的第一个式子枚举出来,很明显dfs里面放一个for对吧,就好比数字4,那他有4个等式,每个等式第一个数字分别是4,3,2,1,比如我们拿第二个等式,枚举完3后,那4-3剩下的部分就继续dfs,让他继续分解,不过要注意后面的分解出来的数比前面的要小。
#include<iostream>
#include<cstdio>
using namespace std;
int book[12];
int num;
void dfs(int n,int pri)//pri表示前面的数值
{
if(n<=0)
{
printf("%d",num);
int pos=1;
for(int i=num;i>=0;i--)
{
for(int j=1;j<=book[i];j++)
{
if(pos)
{
printf("=");
pos=0;
}
else printf("+");
printf("%d",i);
}
}
printf("\n");
return;
}
for(int i=n;i>=1;i--)
{
if(i>pri)
{
continue;
}
book[i]++;
dfs(n-i,i);
book[i]--;
}
return;
}
int main ()
{
scanf("%d",&num);
dfs(num,12);
return 0;
}
18714 迷宫问题
时间限制:1000MS 代码长度限制:10KB
提交次数:0 通过次数:0
题型: 编程题 语言: 不限定
Description
迷宫是一个n*m的矩阵,玩家需要迷宫入口(坐标1,1)出发,寻找路径走到出口(n,m)。
请判断玩家能否从迷宫中走出。
输入格式
第一行两个整数n和m,代表n行m列。(1<=n,m<=10)
下面n行每行m个字符,0代表可以通行,1代表不可以通行。
输出格式
如果能从迷宫走出,输出yes,否则输出no。
输入样例
8 8
00100010
00100010
00001100
01110000
00010000
01000100
01110110
00001000
输出样例
yes
提示
样例数据即为图片迷宫
题解:直接dfs或者bfs模板
#include<iostream>
#include<queue>
#include<cstdio>
using namespace std;
char mmap1[20][20];
int mmap[20][20];
int book[20][20];
int next1[4][2]={
{
1,0},{
0,1},{
-1,0},{
0,-1} };
int main ()
{
queue<pair<int,int> > que;
int n,m;
scanf("%d%d",&n,&m);
getchar();
for(int i=0;i<n;i++)
{
gets(mmap1[i]);
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
mmap[