学习总结7

# 【模板】单调栈

## 题目描述

给出项数为 n 的整数数列 a[1 …… n]$。

定义函数 f(i) 代表数列中第 i 个元素之后第一个大于 ai 的元素的下标,即 f(i)=min{i ai] {j}。若不存在,则 f(i)=0。

试求出 f(1…… n)。

## 输入格式

第一行一个正整数 n。

第二行 n 个正整数 a{1…… n}$。

## 输出格式

一行 n 个整数表示 f(1), f(2), ……, f(n) 的值。

## 样例 #1

### 样例输入 #1

```
5
1 4 2 3 5
```

### 样例输出 #1

```
2 5 4 5 0
```

## 提示

【数据规模与约定】

对于 30% 的数据,n<= 100;

对于 60% 的数据,n<= 5 * 10^3 ;

对于 100% 的数据,1 <= n<= 3* 10^6,1<= ai<= 10^9。

解题思路

单调栈与单调队列很像一样的要维持栈内的单调性,主要的是我用了栈的函数好很多。

代码

#include 
using namespace std;
int  g[40000001];
stack  j;
int g1[40000001];
int main()
{
    int x,n;
    scanf("%d",&n);
    for(x=1;x<=n;x++)
        scanf("%d",&g[x]);
    for(x=1;x<=n;x++)
    {
        while(!j.empty()&&g[x]>g[j.top()])     //栈不空并且要入栈的大于栈顶的数字
        {
            if(!g1[j.top()])
            g1[j.top()]=x;
            j.pop();                           //栈顶出栈
        }
        j.push(x);
    }
    for(x=1;x<=n;x++)
        printf("%d ",g1[x]);
    return 0;
}

# [COCI2010-2011#7] GITARA

## 题目背景

Darko 有一个想象的外星朋友,他有十亿根手指。外星人快速拿起吉他,在网上找到一段简单的旋律并开始弹奏。

这个吉他像寻常一样有六根弦,令其用 1 到 6 表示。每根弦被分成 P 段,令其用 1 到 P 表示。

旋律是一串的音调,每一个音调都是由按下特定的一根弦上的一段而产生的(如按第 4 弦第 8 段)。如果在一根弦上同时按在几段上,产生的音调是段数最大的那一段所能产生的音调。

例:对于第 3 根弦,第 5 段已经被按,若你要弹出第 7 段对应音调,只需把按住第 7 段,而不需放开第 5 段,因为只有最后的一段才会影响该弦产生的音调(在这个例子中是第 7 段)。类似,如果现在你要弹出第 2 段对应音调,你必须把第 5 段和第 7 段都释放。

请你编写一个程序,计算外星人在弹出给定的旋律情况下,手指运动的最小次数。

## 题目描述

你有一个 6 * P 的矩阵 A,初始状态皆为 0。

对于所有要求 (i,j)

你需要满足要求:

1. 此时 Ai,j 状态为 1。

2. 对于 Ai,j+k (k>0) 状态为 0。

你在满足要求的情况下需要求状态转换最小次数。

## 输入格式

第一行包含两个正整数 n ,P。它们分别指旋律中音调的数量及每根弦的段数。

下面的 n 行每行两个正整数 i ,j,分别表示能弹出对应音调的位置——弦号和段号,其为外星人弹奏的顺序。

## 输出格式

一个非负整数表示外星人手指运动次数最小值。

## 样例 #1

### 样例输入 #1

```
5 15
2 8
2 10
2 12
2 10
2 5
```

### 样例输出 #1

```
7
```

## 样例 #2

### 样例输入 #2

```
7 15
1 5
2 3
2 5
2 7
2 4
1 5
1 3
```

### 样例输出 #2

```
9
```

## 提示

#### 样例 1 解释
所有的音调都是由第二根弦产生的。首先按顺序按 8 10 12 (count=3)。然后释放第 12 段(count=4)。最后,按下第 5 段,释放第 8 10 段 (count=7)。

#### 样例 2 解释 
对于每个操作,分别需要 1 1 1 1 3 0 2 次手指运动。

#### 数据规模及约定


按下或释放一段弦各计一次手指运动。弹弦不算手指的移动,而是一个弹吉他的动作。(指你不需要管他怎么弹的,只需要按就是啦,说不定他可以用超能力呀)

对于 100% 的数据 n <= 5 * 10^5 ,2 <= P <= 3 <= 10^5

解题思路

也是栈和模拟的运用,不过在这题每一根手指为一个栈,用一个变量来保存手指移动的次数。

代码

#include 
#include 
using namespace std;
int a[7][4000000];
int b[7];
int main()
{
    int n,p,i,j;
    int x,y,z,t=0;
    scanf("%d%d",&n,&p);
    for(x=0;x=1&&ja[i][b[i]])
        {
            a[i][++b[i]]=j;
            t++;
        }
    }
    printf("%d",t);
    return 0;
}

# [NOIP2013 普及组] 表达式求值

## 题目背景

NOIP2013 普及组 T2

## 题目描述

给定一个只包含加法和乘法的算术表达式,请你编程计算表达式的值。

## 输入格式

一行,为需要你计算的表达式,表达式中只包含数字、加法运算符 `+` 和乘法运算符 `*`,且没有括号,所有参与运算的数字均为 0 到   2^31-1 之间的整数。  

输入数据保证这一行只有 `0123456789+*` 这 12 种字符。

## 输出格式

一个整数,表示这个表达式的值。  

注意:当答案长度多于 4 位时,请只输出最后  4 位,前导  0 不输出。

## 样例 #1

### 样例输入 #1

```
1+1*3+4
```

### 样例输出 #1

```
8
```

## 样例 #2

### 样例输入 #2

```
1+1234567890*1
```

### 样例输出 #2

```
7891
```

## 样例 #3

### 样例输入 #3

```
1+1000000003*1
```

### 样例输出 #3

```
4
```

## 提示

对于 30% 的数据,0≤ 表达式中加法运算符和乘法运算符的总数 ≤100。

对于 80% 的数据,0≤ 表达式中加法运算符和乘法运算符的总数 ≤1000。

对于 100% 的数据,0≤ 表达式中加法运算符和乘法运算符的总数 ≤100000。

解题思路

这上面一样,栈的运用。先把数组中的所有乘法进行运算,然后再进行加法运算,记得把数据都求余。

代码

#include 
#include 
using namespace std;
char g[200000000];
long long j[200000000];
int main()
{
    long long sum=0,x=0,y=0,a=0,b=0;
    scanf("%s",g);
    for(x=0;g[x]!='\0';x++)
    {
        if(g[x]<='9'&&g[x]>='0')             //接收数字
        {
            a=0;
            while(g[x]<='9'&&g[x]>='0')
            {
                a=a*10+g[x++]-'0';
                a%=10000;
            }
        }
        j[++y]=a%10000;
        while(g[x]=='*')                     //进行乘法运算
        {
            x++;
            a=0;
            while(g[x]<='9'&&g[x]>='0')
            {
                a=a*10+g[x++]-'0';
                a%=10000;
            }
            j[y]=(j[y]*a)%10000;
        }
    }
    for(x=1;x<=y;x++)
        sum=(sum+j[x])%10000;
    printf("%lld",sum%10000);
    return 0;
}

# 路障

## 题目描述

B 君站在一个 n * n 的棋盘上。最开始,B君站在 (1,1) 这个点,他要走到 (n,n) 这个点。

B 君每秒可以向上下左右的某个方向移动一格,但是很不妙,C 君打算阻止 B 君的计划。

每秒结束的时刻,C 君 会在 (x,y) 上摆一个路障。B 君不能走在路障上。

B 君拿到了 C 君准备在哪些点放置路障。所以现在你需要判断,B 君能否成功走到 (n,n)。

保证数据足够弱:也就是说,无需考虑“走到某处然后被一个路障砸死”的情况,因为答案不会出现此类情况。

## 输入格式

首先是一个正整数 T,表示数据组数。

对于每一组数据:

第一行,一个正整数 n。

接下来 2n-2 行,每行两个正整数 x 和 y,意义是在那一秒结束后,(x,y) 将被摆上路障。

## 输出格式

对于每一组数据,输出 `Yes` 或 `No`,回答 B 君能否走到 (n,n)。

## 样例 #1

### 样例输入 #1

```
2

2
1 1
2 2

5
3 3
3 2
3 1
1 2
1 3
1 4
1 5
2 2
```

### 样例输出 #1

```
Yes
Yes
```

## 提示

样例解释:

以下 0 表示能走,x 表示不能走,B 表示 B 君现在的位置。从左往右表示时间。

```
Case 1:
0 0    0 0    0 B  (已经走到了)
B 0    x B    x 0
```
```
Case 2:
0 0 0 0 0    0 0 0 0 0    0 0 0 0 0    0 0 0 0 0
0 0 0 0 0    0 0 0 0 0    0 0 0 0 0    0 0 0 0 0
0 0 0 0 0    0 0 x 0 0    0 0 x 0 0    0 0 x 0 0
0 0 0 0 0    0 0 0 0 0    0 0 x 0 0    0 0 x 0 0
B 0 0 0 0    0 B 0 0 0    0 0 B 0 0    0 0 x B 0 ......(B君可以走到终点)
```

数据规模:

防止骗分,数据保证全部手造。

对于 20% 的数据,有 n<=3。

对于 60% 的数据,有 n<=500。

对于 100% 的数据,有 n<=1000。

对于 100% 的数据,有 T<=10。

解题思路

这道题我一开始用的是dfs,但出了点问题会超时。用bfs时也要注意当一开始就是出口时要直接输出, 还有要注意一出口是不是被障碍物挡住了。

代码

#include 
using namespace std;
long long g[1010][1010];
long long j[1010*1010][3];
long long d[1010][2];
long long l,r;
long long n;
long long h[5][2]={{1,0},{-1,0},{0,1},{0,-1}};
long long bfs()
{
    long long tx,ty,x,t=0,z,m;
    while(ln||ty>n)
                continue;
            if(g[tx][ty]==0)
            {
                if(tx==n&&ty==n)
                {
                    return t;
                }
                g[tx][ty]=1;
                j[r][0]=tx;
                j[r++][1]=ty;
            }
        }
        g[d[t][0]][d[t][1]]=2;
        if(g[n][n]==2)
            return 0;
        t++;
        l++;
    }
    return 0;
}
int main()
{
    long long x,y,z,t;
    scanf("%lld",&t);
    for(y=0;y

你可能感兴趣的:(学习,算法,c++)