Week1-2 单调栈与ST表

9.6

思维题:1. Problem - A - Codeforces

 题目大意:在一堆面板中,开始都为0,并逐渐涨1,选择一个面板暂停增长,则其邻板以1秒间隔的递增方式停止增长。例:

假设有4个面板,当第3个面板上有数字9时暂停;

面板1暂停2秒后,所以它有数字1;

面板2暂停1秒后,所以它有数字0;

面板4暂停1秒后,所以它有数字0。

思路:一开始考虑第一个数字为9,后来发现当第二个数字为8时暂停可使整体最大。

代码如下:

#include
#include
#include
#include
#include
using namespace std;
int main()
{
	int t,i,j;
	cin >> t;
	while (t--)
	{
		int n;
		char c = '0';
		cin >> n;
		if (n == 1) cout << "9" << endl;
		else if (n == 2) cout << "98" << endl;
		else if (n == 3) cout << "989" << endl;
		else
		{
			char s[2*100000+10] = "989";
			for (i = 3; i < n; i++)
			{
				if (c == '9')
				{
					s[i] = c;
					c = '0';
				}
				else {
					s[i] = c;
					c = c +'1' - '0';
				}
			}
			s[i] = '\0';
			cout << s << endl;
		}
	}
}	

思维题:2.Problem - B - Codeforces

题目大意:在一组数据中,初始元素为1,经过操作一a*x,和操作二x+b找出是否可以等于n的元素。

思路:由于初始元素为1,经过操作可以变为a^k+qa*tb+......+pb;所以n可以近似=a^k1+k2b;再列举a^k1情况。

代码:

#include
#include
#include
#include
#include
using namespace std;
int main()
{
	int t,i,j;
	cin >> t;
	while (t--)
	{
		long long int n, a, b;
		cin >> n >> a >> b;
		if (a == 1)
		{
			if (n % b == 1|| b==1) cout << "YES" << endl;
			else cout << "NO" << endl;
			continue;
		}
		long long int k = 1,flag=0;
		while (k <= n)//n=a^k1+k2b 列举a^k1
		{
			if ((n - k) % b == 0 && n-k>=0)
			{
				flag = 1;
				break;
			}
			k *= a;
		}
		if (flag) cout << "YES" << endl;
		else cout << "NO" << endl;
	}
}	

专题训练:单调栈 - OI Wiki (oi-wiki.org)

顾名思义,单调栈即满足单调性的栈结构。与单调队列相比,其只在一端进行进出。

为了描述方便,以下举例及伪代码以维护一个整数的单调递增栈为例

插入¶

将一个元素插入单调栈时,为了维护栈的单调性,需要在保证将该元素插入到栈顶后整个栈满足单调性的前提下弹出最少的元素。

例如,栈中自顶向下的元素为1,3,5,10,30,50 ,插入元素20  时为了保证单调性需要依次弹出元素 1,3,5,10,操作后栈变为 。20,30,50.

例题:P5788 【模板】单调栈 - 洛谷 

题目大意:给出一组项数为n的数组,求出第 i 个元素之后第一个大于 a[i]​ 的元素的下标.

思路:运用栈,从后往前插入,小的就弹出。

代码:

#include
#include
#include
#include
#include
#include
using namespace std;
long long int a[3*1000000+10],f[3*1000000+10];
int main()
{
	int n, i, j;

	stackb;
	cin >> n;
	for (i = 1; i <= n; i++)
		cin >> a[i];
	for (i = n; i >= 1; i--)
	{
		while (!b.empty() && a[b.top()] <= a[i]) b.pop();
		if (b.empty()) f[i] = 0;
		else {
			f[i] = b.top();
		}
		b.push(i);
	}
	for (i = 1; i <= n; i++)
		cout << f[i] << " ";
	cout << endl;
	return 0;
}	


9.7

专题练习:B-B 找山坡

题目大意:

给定一个大小为n的数组a,序号从1开始,

计算:max{ R - L | 1 <= L <= R <= n, a[L] == a[R], 对于所有i (L <= i <= R), 满足a[i] >= a[L] }.

也就是找到两个坐标,这两个坐标的值相等,并且他们之间的值都大于等于这两个坐标上的值.

这两个坐标相减最大能是多少。

思路:运用单调栈的模板,从右向左遍历。要满足题目条件:那么首先要满足栈不空&&a[b.top()] <=a[i],当大于时弹出栈顶元素,当两者相等时,记录此时的结果,并与最大值比较取max。

牛客这道题原先ac 50%,之后把while里的j改为i就过了。。。。。。。。确实还是有一点没搞清楚

#include
#include
#include
#include
#include
#include
using namespace std;   
int a[10000000 + 20];
int main()
{
    int n, i, j,len=0,max1=0;
    stackb;
    cin >> n;
    for (i = 1; i <= n; i++)
        cin >> a[i];
    for (i = n; i >= 1; i--)
    {
       j = i;
        while (!b.empty() && a[b.top()] >= a[i])
        {
           if(!b.empty()&& a[b.top()]>a[i])   b.pop();
           else if (!b.empty() && a[b.top()] == a[i]) {
               len = b.top() - i;
               max1 = max(max1, len);
               if (i == 1) b.pop();
               else i--;
           }          
        }
        b.push(i);
    }
    cout << max1 << endl;
    return 0;
}	

 

9.8

专题练习:402. 移掉 K 位数字 - 力扣(LeetCode) (leetcode-cn.com)

第一次写leetcode

题目大意:给你一个以字符串表示的非负整数 num 和一个整数 k ,移除这个数中的 k 位数字,使得剩下的数字最小。请你以字符串形式返回这个最小的数字。

思路:先看测试数据规律发现:当字符串单调递增的变化发生改变,则删除递增的最后一个数字,运用单调栈重复此步骤。最后是删除前导0。

注意:1.当k等于字符串长度要单独讨论。2.pop_back()可以删除字符串最后一个字符,reverse可以调换整个字符串的顺序。3.这样定义 string s1="" 似乎就不会出现内存错误。

代码

class Solution {
public:
    string removeKdigits(string num, int k) {
    stack s;
    int i,j;
    int count=0;
    if(k==num.length()) return "0";
    for(i=0;i

9.9 

专题练习:316. 去除重复字母 

题目大意:给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。

思路参考:Revendell的博客-CSDN博客

基本思想:单调栈,有条件限制的单调栈,遇到一个新字符如果比栈顶小并且在新字符后面还有和栈顶一样的就把栈顶的字符抛弃了。

正确代码:

class Solution {
public:
    string removeDuplicateLetters(string s) {
             stackb;
             string s1;
             int i ,j;
             vectorvec(26),cou(26);
              for(i=0;i0)
                 {   
                   cou[s[b.top()]-'a']=0;
                       b.pop();
                  
                 }
                 b.push(i);
                 cou[s[b.top()]-'a']=1;
             }
             for(i=0;!b.empty();i++)
             {
                 s1=s[b.top()]+s1;
                 b.pop();
             }
             return s1;
    }
};

错误代码:

class Solution {
public:
    string removeDuplicateLetters(string s) {
             stackb;
             string s1;
             int i ,j;
             vectorvec(26),cou(26);
              for(i=0;i=2)
                 {   
                   vec[s[b.top()]-'a']--;//错误点,vec应该记录s[i]之后的与s[i]相同的字符个数,而不是总数减掉1.
                   cou[s[b.top()]-'a']=0;
                       b.pop();
                  
                 }
                 b.push(i);
                 cou[s[b.top()]-'a']=1;
             }
             for(i=0;!b.empty();i++)
             {
                 s1=s[b.top()]+s1;
                 b.pop();
             }
             return s1;
    }
};
 

9.10

思维题 2021.9 Contest 1 - Virtual Judge (vjudge.net)

题目大意:周赛题目(居然都不会做)博弈。

#include
#include
#include
#include
#include
#include
using namespace std;
int main()
{
    std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	double n,t;
	long long int k, count = 0,p;
	while (cin >> n)
	{
		while (n > 18)
			n /= 18;
		if (n > 9) cout << "Ollie wins." << endl;
		else
			cout << "Stan wins." << endl;
	}
	return 0;
}	

对博弈如此不熟悉

P1288 取数游戏II - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include
#include
#include
#include
#include
#include
using namespace std;
int main()
{
	int n,i,j,count=0;
	int a[20 + 4];
	cin >> n;
	for (i = 1; i <= n; i++)
	{
		cin >> a[i];
		if (a[i]) count++;
	}
	if (count % 2 == 1) cout << "YES" << endl;
	else cout << "NO" << endl;
	return 0;
}

9.13:ST 表 - OI Wiki (oi-wiki.org)

稀疏表暑假训练ppt提到过,但是没练过。

P3865 【模板】ST 表 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

模板题

#include
#include
#include
#include
using namespace std;	
inline int read()
{
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;//快速写入
}
int ma[1000110][19];
int query(int l, int r)
{
	int k = log2(r - l + 1);
	return max(ma[l][k], ma[r - (1 << k) + 1][k]);
}
int main()
{
    std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int n, m,i,j;
	n=read();
	m=read();
	for (i = 1; i <=n; i++)
	{
		ma[i][0] = read();
	}
	for (j = 1; j <= 19; j++)
	{
		for (i = 1; i + (1 << j) - 1 <= n; i++)//预防超出范围
		{
			ma[i][j] = max(ma[i][j - 1], ma[i + (1 << (j - 1))][j - 1]);//ma[i][j]表示从i开始1<


CF1512G Short Task - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

周赛补题

#include
#include
#include
#include
#include
#include
using namespace std;	
int ans[10000000+10];
long long int d[10000000 + 10];
int main()
{
std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t, n,i,j;
		for (i = 1; i <= 10000000; i++)
		{
			for (j = 1; j <= 10000000 / i; j++)
			{
				d[i * j] += i;
			}
		}
		for (i = 1; i <= 10000000; i++)
		{
			if (d[i] > 10000000) continue;
			if (ans[d[i]] == 0) ans[d[i]] = i;
			else
			{
				ans[d[i]] = min(ans[d[i]], i);
			}
		}
	cin >> t;
	while (t--)
	{
		int i, j;
		cin >> n;
		
		if (!ans[n]) cout << "-1" << endl;
		else cout << ans[n] << endl;
	}
	
}

9.15

思维题:Problem - D1 - Codeforcesz    

题目大意:一排人 数组a表示各个人的视力,s表示做的位置,如果a[i]

思路:完全可以按照视力大小排位置,例如 视力a[i] 那么s[i]=a[i]。最后判断枚举。

#include
#include
#include
#include
#include
#include
using namespace std;
int main()
{
	int t, m, n,i,j;
	int a[400];
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> t;
	while (t--)
	{
		cin >> n >> m;
		for (i = 1; i <= m; i++)
		{
			cin >> a[i];
		}
		int  sum = 0;
		for (i = 1; i <= m; i++)
		{
			for (j = 1; j < i; j++)
				if (a[j] < a[i]) sum++;
		}
		cout << sum << endl;
	}
	return 0;
}

专题:LibreOJ (loj.ac)    (没做出来)

题意:给你一组 年份和对应降水量,再询问某一区间内最后一项是否大于除第一项外的降水量。

思路:先分情况 1.当左边界和右边界都不确定时。则maybe。2.当左边界不确定,右边界确定时,如果中间降雨量大于右边界,输出false,否则maybe。3.当左边确定,右边不确定,如果中间量大于等于左边界,输出false,否则maybe。4.都确定时,右边界大于左边界,或者中间量大于等于右边界 输出false,如果中间量you不确定的,输出maybe,否则true。

用map存入年份和对应编号(1,2,3,4----),用b数组存入降雨量,再用ST表模板查找最大值。

错误代码:

#include
#include
#include
#include
#include
#include
using namespace std;
mapa;
int b[50000 + 10];
inline int read()
{
	char c = getchar(); int x = 0, f = 1;
	while (c < '0' || c>'9') { if (c == '-')f = -1; c = getchar(); }
	while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
	return x * f;//快速写入
}
int ma[1000110][19];
int query(int l, int r)
{
	if (l > r) return 0;//判断特例
	int k = log2(r - l + 1);
	return max(ma[l][k], ma[r - (1 << k) + 1][k]);
}
int main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int n, m, i, j;
	n = read();
	for (i = 1; i <= n; i++)
	{
		int year, rain;
		year = read();
		rain = read();
		a[year] = i;
		b[i] = rain;
		ma[i][0] = rain;
	}
	for (j = 1; (1<= b[a[r]])
			{
				cout << "false" << endl;
				continue;
			}
			else
			{
				cout << "maybe" << endl;
				continue;
			}
		}
		else if (a[l] && !a[r])
		{
			int ans = query(a[l] + 1, a[r] - 1);
			if (b[a[l]] <= ans)
			{
				cout << "false" << endl;
				continue;
			}
			else cout << "maybe" << endl;
			continue;
		}
		else
		{
			int ans;
			ans = query(a[l] + 1, a[r] - 1);
			if (ans >= b[a[r]] || b[a[r]] > b[a[l]])
			{
				cout << "false" << endl;
				continue;
			}
			else if(a[r]-a[l]!=(r-l))
			{
				cout << "maybe" << endl;
				continue;
			}
			else
			{
				cout << "true" << endl;
			}
		}
	}
}


9.16

补题  Codeforces Global Round 16 - Codeforces

思维:Problem - D2 - Codeforces

题目大意:跟D1相同,n变为<300

思路:先根据视力大小排序,确定一行。对于每一行,如果视力相同,那么排在前面的进入到后一点的位置去,这样可以使总值最小。

参考: Codeforces Global Round 16 A-E_roadtohacker的博客-CSDN博客

#include
#include
#include
#include
#include
#include
#include
using namespace std;
int main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t, m, n, i, j;
	cin >> t;
	while (t--)
	{
		cin >> n >> m;
		vector> a(n * m);
		for (i = 0; i < n*m; i++)
		{
			cin >> a[i].first;
			a[i].second = i;
		}
		sort(a.begin(), a.end());
		int  sum = 0;
		int k;	
		for (int i = 0; i < n * m; i++) {
			a[i].second = -a[i].second;
		}
		for (i = 0; i < n; i++)
			sort(a.begin() + i * m, a.begin() + i * m + m);
		for (i = 0; i < n; i++)
		{
				for (k = 0; k < m; k++)
				{
					for (j = 0; j < k; j++)
						if (a[i*m+j].second>a[i*m+k].second) sum++;
				}
		}
		cout << sum << endl;
	}
	return 0;
}

专题:P2880 [USACO07JAN]Balanced Lineup G - 洛谷 

思路:用两次st模板,分别求最大和最小。再相减作差。

#include
#include
#include
#include
using namespace std;
inline int read()
{
	char c = getchar(); int x = 0, f = 1;
	while (c < '0' || c>'9') { if (c == '-')f = -1; c = getchar(); }
	while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
	return x * f;//快速写入
}
int ma[1000110][19];
int mp[1000110][19];
int query(int l, int r)
{
	int k = log2(r - l + 1);
	return max(ma[l][k], ma[r - (1 << k) + 1][k])-min(mp[l][k], mp[r - (1 << k) + 1][k]);
}
int main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int n, m, i, j;
	n = read();
	m = read();	
	for (i = 1; i <= n; i++)
	{
		mp[i][0]=ma[i][0] = read();
	}
	for (j = 1; j <= 19; j++)
	{
		for (i = 1; i + (1 << j) - 1 <= n; i++)//预防超出范围
		{
			ma[i][j] = max(ma[i][j - 1], ma[i + (1 << (j - 1))][j - 1]);//ma[i][j]表示从i开始1<

你可能感兴趣的:(算法,概率论)