数组
1、在一个数组中,一部分被标记了,找出未标记部分的最小值。
#include <cstdio>
using namespace std;
bool st[10];
int main(){
int q[10]={8,2,19,6,0,-2,-9,20,23,-7};
int n;
scanf("%d",&n);
for(int i=0;i<n;i++){ //标记了n个点
int a;
scanf("%d",&a);
st[a]=true;
}
int t=-1; //开始找最小值,这是一种最新的简单写法
for(int i=0;i<10;i++){
if(!st[i]&&(t==-1 || q[t]>q[i])){
t=i;
}
}
printf("%d\n",q[t]);
return 0;
}
1、更新思维
先看一个简单的例子,输入一些数,找出最小值。
常规做法,先把这些数存入数组,再从数组中找到最小值。
for(int i=0;i<n;i++) scanf("%d",&a[i]);
int t=-1;
for(int i=0;i<n;i++){
if(t==-1 || a[i]<a[t]) t=i;
}
printf("%d\n",a[t]);
但其实,输入数据的同时,可以顺便更新最小值
int t=-1;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
if(t==-1 || a[i]<a[t]) t=i;
}
printf("%d\n",a[t]);
2、上例是一个简单的说明,事实上这种思维,再很多大题也常用。
在图论中,集合外有一点x和集合内三点a,b,c都有边,求x和集合的最短边
常规思路自然是,把xa,xb,sc都拿出来比一比,找出最小边。但若是集合内的点是动态加入的呢?
比如上题,一些数是逐个输入的。沿着上题的思路,我在逐个往集合放入点时,能否顺便更新一下,
正在放入集合的点与x的距离,使之保持一个最短距离呢?答案是肯定的,而且,这才是正确的思路。
因为我们在放入集合点的同时,更新了和x的距离,这样少写一个n的循环。
这样做还有一个原因,如果集合外有很多点都要和集合保持最短距离呢?即多对多的保持最短,这样
就可以少写一个$O(N^2)$的循环了.例题是:858题
字符串
scanf读取字符使用%c时,会把空格,换行符等空白都进来,但cin就可以忽略这些空白
输入:“a b c”,输出“abc”
for(int i=0;i<3;i++){
char c;
scanf("%c",&c); //错误,会把空白读进来
printf("%c",c);
}
用cin就没有问题
string s;
for(int i=0;i<3;i++){
char c;
cin>>c;
s+=c;
}
cout<<s<<endl;
但是,scanf可以改用%s格式串解决此问题;
char s[10]=""; //必须初始化为空字符串,否则strcat会出错。
for(int i=0;i<3;i++){
char c[2];
scanf("%s",c);
strcat(s,c);
}
puts(s);
一次成型的优化
计算$4x^3+3x^2+2x+1$的解,如果分步计算每个分式的话,就需要大循环套小循环来做,其实可以用一个循环解决:
int a[]={4,3,2,1};
int y=0;
for(int i=0;i<4;i++){
y=y*x+a[i];
}
看一下运行过程:
当i=0时,y=0+4,y=4;
当i=1时,y=4x+3;
当i=2时,y=(4x+3)*x+2,$y=4x^2+3x+2$
当i=3时,$y=(4x^2+3x+2)\cdot x + 1,y=4x^3 + 3x^2 + 2x + 1$
正好是需要的算式,在最后一步才最终成型。
例题2:还有在快读中也是这种一次成型的思维:
while(ch>='0' && ch<='9'){
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}
学习时,一个模板有时候最有价值的并不是它能解决的问题,而是它的思路本身,在众多题型中变化。