9.20日志

算法板块

例题1.1087. 修剪草坪 - AcWing题库

我们用一段的终点来划分区间,dp[i]表示的是前i头牛的最大效率,首先考虑第i头牛选不选,若不选则dp[i] = dp[i - 1],若选则需要考虑上一个断点在哪个位置,上一个断点的位置在[i - k + 1 ~ i - 1]的位置,因此想到单调队列优化,因为是区间和因此还需要用到前缀和优化,若选择第i头牛则dp[i] = dp[i - x - 1] + a[i] - a[i - x],也就是要找到dp[i - x - 1] - a[i - x]的最大值,我们把这一项用滑动窗口进行维护即可.

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;    
const int N = 3e5 + 10;
const ll inf = 1e18;

int n,k;
ll a[N],dp[N];
ll q[N];

ll g(int x)
{
    if(x == 0)
    {
        return 0;
    }else
    {
        return dp[x - 1] - a[x];
    }   
}

int main()
{
    cin>>n>>k;

    for(int i = 1 ; i <= n ; i++)
    {
        cin>>a[i];
        a[i] += a[i - 1];
    }        

    int tt = -1,hh = 0;
    q[++tt] = 0;
    for(int i = 1 ; i <= n ; i++)
    {
        while(hh <= tt && q[hh] < i - k)
        {
            hh++;
        }
        while(hh <= tt && g(q[tt]) <= g(i))
        { 
            tt--;
        }
        dp[i] = max(dp[i - 1] , a[i] + g(q[hh]));
        q[++tt] = i;
    }

    cout<<dp[n];
}

今天打了一下牛客小白月赛,只ac了3题,属于是屎中屎了,赛后5min出了d,并不难,明天有机会把e也给补了

1.A-tb的区间问题_牛客小白月赛101 (nowcoder.com)

一开始的思路是k次循环,每次比较首元素和尾元素,谁小删哪个,这是一个错误的贪心思路,例如k = 2的时候数组是8 7 1 8或者8 1 7 8总有一个能卡住这个思路,所以不妨采取逆向思维,我们看保留的n - k个数,一定是一个连续的n - k个数,那么就找sum最大的连续的n - k个数即可。

#define first x
#define second y
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll , ll> pii;
typedef pair <int , char> pic;
const int N = 1e5 + 10,inf = 0x3f3f3f3f,mod = 998244353;

int n,k;
ll a[N];

int main()
{
	std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);

	cin>>n>>k;

	ll maxn = -1;
	for(int i = 1 ; i <= n ; i++)
	{
		cin>>a[i];
		a[i] += a[i - 1];
	}

	for(int i = 1 ; i + n - k <= n ; i++)
	{
		maxn = max(maxn , a[i + n - k] - a[i]);
	}

	cout<<maxn;
}

2.B-tb的字符串问题_牛客小白月赛101 (nowcoder.com)

类似于括号匹配的问题,那么就是用栈来维护,当遇到f或者t的时候就入栈,遇到c或者b的时候就看是否能与栈顶匹配,若能匹配两两相消,否则清空栈,若是其他字符也是清空

#define first x
#define second y
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll , ll> pii;
typedef pair <int , char> pic;
const int N = 1e5 + 10,inf = 0x3f3f3f3f,mod = 998244353;

int n;
string s;

int main()
{
	std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);

	cin>>n>>s;

	stack <char> stk;
	int len = 0;
	for(int i = 0 ; i < n ; i++)
	{
		if(s[i] == 'f')
		{
			stk.push('f');
		}else if(s[i] == 't')
		{
			stk.push('t');
		}else if(s[i] == 'c' && stk.size())
		{
			if(stk.top() == 'f')
			{
				stk.pop();
				len += 2;
			}else
			{
				stack <char>().swap(stk);
			}
		}else if(s[i] == 'b' && stk.size())
		{
			if(stk.top() == 't')
			{
				stk.pop();
				len += 2;
			}else
			{
				stack <char>().swap(stk);
			}
		}else
		{
			stack <char>().swap(stk);
		}
	}

	cout<<n - len;
}

 3.C-tb的路径问题_牛客小白月赛101 (nowcoder.com)

输出几张地图可以发现,当是偶数的时候gcd(n - 2 , n) == 2,对角线上的元素是i,那么偶数的时候4步就能走到,奇数的时候可以由偶数转移,通过4步走到n - 1后再走两步到n。

#define first x
#define second y
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll , ll> pii;
typedef pair <int , char> pic;
const int N = 1e6 + 10,inf = 0x3f3f3f3f,mod = 998244353;

int n;
int ans[N];

int main()
{
	std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);

	cin>>n;
	ans[1] = 0;
	ans[2] = 2;
	
	for(int i = 3 ; i <= n ; i++)
	{
		if(__gcd(i - 2 , i) == 2)
		{
			ans[i] = 4;
		}else
		{
			ans[i] = ans[i - 1] + 2;
		}
	}
	
	cout<<ans[n];
}

4.D-tb的平方问题_牛客小白月赛101 (nowcoder.com)

观察到n很小,支持双重循环,那么我们就通过前缀和枚举所有区间的区间和,若该区间和是完全平方数那么就在ans数组中[i , j]差分加1即可,最后o1输出即可

#define first x
#define second y
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll , ll> pii;
typedef pair <int , char> pic;
const int N = 1e5 + 10,inf = 0x3f3f3f3f,mod = 998244353;

int n,q;
ll a[N];
ll s[N],ans[N];

void insert(int x,int y)
{
	ans[x]++;
	ans[y + 1]--;
}

int main()
{
	std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);

	cin>>n>>q;

	for(int i = 1 ; i <= n ; i++)
	{
		cin>>a[i];
		s[i] = s[i - 1] + a[i];
	}

	for(int i = 1 ; i <= n ; i++)
	{
		for(int j = i ; j <= n ; j++)
		{
			ll sum = s[j] - s[i - 1];
			ll t = sqrt(sum);
			if(t * t == sum)
			{
				insert(i , j);
			}
		}
	}
	
	for(int i = 1 ; i <= n ; i++)
	{
		ans[i] += ans[i - 1];
	}

	while(q--)
	{
		int x;
		cin>>x;
		cout<<ans[x]<<"\n";
	}
}

晚上又打了一场cf,做了三题,前两题十分水就不记录了,第三题是一道交互题,还是蛮有意思的,但是一开始想复杂了,只要一步步走思路还是比较好想的,猜一个二进制的数字,告诉你一共有n位,要求在2n次以内猜出来,那么我们只需要一位一位的猜即可,首先是每次向前拓展还是向后拓展,我们默认是向前拓展,当出现向前加0加1都不对的时候就要向后拓展了,我们默认每次拓展一个0,如果不对就把0改成1若对则继续下一位数字的循环若不对则说明我们已经猜出所有前缀,接下来往后猜,一样的思路,只不过我们此时不需要在加0错误后验证加1是否正确,若加1后s的长度小于n那么我们可以在提问验证之前再加一次0,若长度为n了那么退出即可。

#define first x
#define second y
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll , ll> pii;
typedef pair <int , char> pic;
const int N = 2e5 + 10,inf = 0x3f3f3f3f,mod = 998244353;

void work()
{
	int n;
	cin>>n;

	string s;
	s = "0";

	int cnt = 0,l = 1,r = 0;
	while(1)
	{
		cout<<"? "<<s<<"\n";
		cout<<flush;
		int f;
		cin>>f;
		
		if(f && s.size() == n)
		{
			break;	
		}
		
		if(l)
		{
			if(f)
			{
				s.insert(0 , "0");
				cnt = 0;
			}else if(cnt == 0)
			{
				s.erase(0 , 1);
				s.insert(0 , "1");
				cnt++;
			}else
			{
				s.erase(0 , 1);
				s += "0";
				cnt = 0;
				l = 0,r = 1;
			}
		}else
		{
			if(f)
			{
				s += "0";
				cnt = 0;
			}else if(cnt == 0)
			{	
				s.erase(s.size() - 1 , 1);
				s += "1";
				if(s.size() == n)
				{
					break;
				}else
				{
					s += "0";
				}
			}
		}
	}

	cout<<"! "<<s<<"\n";
	cout<<flush;
}

int main()
{
	std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);

	int t;
	cin>>t;

	while(t--)
	{
		work();
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值