Codeforces Round #546 (Div. 2)

A题
k表示停留在第几页,表示没有读这一页前面全部读过了。问还有多少章没有读
遍历一遍章节的l,r 如果k在里面表示一定这一章和后面的所有都没有读。

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
int n;
int k;
int l[105],r[105];
int main()
{
	n = read();
	up(i, 0, n)
		cin >> l[i] >> r[i];
	k = read();
	int ans = 0;
	up(i, 0, n)
	{
		if (l[i] <= k && k <= r[i])
		{
			ans = n - i;
			break;
		}
	}
	cout << ans << endl;
	return 0;
}

B题
三种操作,第一做一步,第二扔一个石头向其他的地方,第三个是打开这个地方的宝藏。
问最少操作使得拿完所有的宝藏。
我们可以发现,把石头扔到走过的地方一定是最优解,因为不用重新扔石头了。
所以除了第一部和第二部,也就是题目所给的22那种情况外,都可以这样做。
先做22,就可以清空自己源点所在区域,往后面走时把石头扔向源点。
除了第一步,后面都是3步,仍一块石头,打开,往前走。
这里注意先向左走和向右走是不同的,因为回溯的步数不一样。

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
int n, k;
int val[5005];
int main()
{
	n = read();
	k = read();
	upd(i, 1, n)val[i] = 1;
	int ans = 0;
	if (k == 1)
	{
		if (n == 2)
		{
			cout << 6 << endl;
		}
		else
		{
			cout << 6 + (n - 2) * 3 << endl;
		}
	}
	else  if (k == n)
	{
		if (n == 2)cout << 6 << endl;
		else 
		{
			cout << 6 + (n - 2) * 3 << endl;
		}
	}
	else
	{
		if (n == 2)cout << 6 << endl;
		else if (k <= n / 2)
		{
			cout << 6 + (k - 2) * 3 + k - 1 + (n - k) * 3 << endl;
		}
		else cout << 6 + (n - k - 1) * 3 + n - k + (k - 1) * 3 << endl;
	}
	return 0;
	
}

C题。
给出两个矩阵 a,b。可以对a的子矩阵做专制,问是否可以让a==b。
我们可以发现,矩阵对角线上的元素可以任意移动,只需要做2x2的方阵不断在对角线上移动即可。
所以我们对对角巷上的所有元素进行排序。如果a=b说明可以,否则无解。(对角线上的元素只能在对角线上移动。)

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
int n, m;
int a[505][505], b[505][505];
int main()
{
	n = read();
	m = read();
	up(i, 0, n)
	{
		up(j, 0, m)
		{
			a[i][j] = read();
		}
	}
	up(i, 0, n)
		up(j, 0, m)
		b[i][j] = read();
	vector<int >veca[2000];
	vector<int >vecb[2000];
	int tempa = 0, tempb = 0;
		for (int i = 0;i <n; i++)
		{
			for (int j = i, cnt = 0; j >= 0 && cnt < m; j--, cnt++)
			{
				veca[tempa].push_back(a[j][cnt]);
				vecb[tempa].push_back(b[j][cnt]);
			}
			tempa++;
		}
		up(i, 1, m)
		{
			for (int j = n - 1, cnt = 0; j >= 0 && cnt+i < m; j--, cnt++)
			{	
				veca[tempa].push_back(a[j][cnt + i]);
				vecb[tempa].push_back(b[j][cnt + i]);
			}
			tempa++;
		}
		up(i, 0, tempa)
		{

			sort(veca[i].begin(), veca[i].end());
			sort(vecb[i].begin(), vecb[i].end());
		}
		up(i, 0, tempa)
		{
			up(j, 0, veca[i].size())
			{
			//	cout << "i" << i << "j" << j << " " << veca[i][j] << vecb[i][j] << endl;

				if (veca[i][j] != vecb[i][j])
				{
					cout << "NO" << endl;
					return 0;
				}
			}
		}
	cout << "YES" << endl;
	return 0;
}

D题
给出初始的排队顺序,然后又pair(a,b)表示如果a刚好在b前面,ab交换位置。问最后一个人最远能移动到哪里。
没看见directly,一开始以为是水题
很明显,最后一个人一直能和n-1的人换位置,而换到n-1又只能和n-2的人交换顺序。
所以,要是前面的人可以和当前位置交换,满足。
n-ans-i<=cnti,其中cnt表示从当前位置到i一共和i有对少对互通,ans表示从末尾往前看的第几位。
所以只要叫在中间的人都和i有贡献,那么就可以让最后一位前进一位。
注意的是,如果当前狡猾了位置,那么下一位的贡献中就不能计算当前位置的贡献了,因为当前位置已经被替换上去了。即abcde,be交换后成为acdeb,那么a考虑的贡献就还是cde,没有b。
注意时间复杂度不是n2是n+m,因为m中的pair只会转移一次。

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
int n, m;
bool cmp(pair<int ,int >a,pair<int ,int >b)
{
	return a.second == b.second ? a.first > b.first: a.second > b.second;
}
const int N = 3e5 + 10;
int a[N];
int pos[N];
vector<int >vec[N];
int cnt[N];
int main()
{
	n = read();
	m = read();
	upd(i, 1, n)
	{
		a[i] = read();
		pos[a[i]] = i;
	}
	int x, y;
	up(i, 0, m)
	{
		x = read(), y = read();
		vec[y].push_back(x);
	}
	for (auto x : vec[a[n]])
	{
		cnt[x]++;
	}
	int ans = 0;
	dwd(i, n - 1, 1)
	{
		if (cnt[a[i]]  >= n - ans - i)ans++;
		else 
			for (auto x : vec[a[i]])
			{
				cnt[x]++;
			}
	}
	cout << ans << endl;
	return 0;
}

E题
观察可以发现,a序列+x后,改变的量是具有单调性的,所以某位置j不会被修改了,那么j后面的也同样不会被修改了。
对于查询。建立线段树。
没有更改的位置就是他自己。
对于更改过的位置(x,y),我们进行更新。
有sumxy=a[x]+a[x]+k[x]+a[x]+k[x]+k[x+1]。。。。发现一共会有y-x+1个a[x],而k[x]的前面的系数为y-x,y-x-1.。。。。。
我们开两个数组预处理。第一个数组b预处理出k[x]的前缀和。
第二个c数组处理b数组的前缀和。
就有了c[x]=x*k[1]+(x-1)*k[2]。。。。。所以就可以给出线段树需要更新的值。
val=(r-l+1) *(a[l]-b[l])+c[r]-c[l-1],这里左右子树合并刚好可以直接合并不影响其他的,所以直接把这个值放到线段树中去更新就好了。(其中b,c,数组直接从2开始,方便直接使用因为和原数组a差一位)

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 1e18;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
const int N = 2e5 + 10;
int q;
int n;
ll tree[N << 1], sum[N << 1],lazy[N<<1];
ll b[N], c[N];
void pushup(int root) { tree[root] = tree[root << 1] + tree[root << 1 | 1]; }
void pushdown(int root,int l,int r)
{
	if (lazy[root] != -INF)
	{
		int mid = (l + r )>> 1;
		tree[root << 1] = c[mid] - c[l - 1] + (mid - l + 1)*lazy[root];
		tree[root << 1 | 1] = c[r] - c[mid] + (r - mid)*lazy[root];
		lazy[root << 1] = lazy[root << 1 | 1] = lazy[root];
		lazy[root] = -INF;
	}
}
void build(int l, int r,int root)
{
	lazy[root] = -INF;
	if (l == r)
	{
		scanf("%lld", &tree[root]);
		return;
	}
	int mid = (l + r) >> 1;
	build(l, mid, root << 1);
	build(mid + 1, r, root << 1 | 1);
	pushup(root);
}
ll querry(int l, int r, int L, int R,int root)
{
	if (L <= l && r <= R)
	{
		return tree[root];
	}
	pushdown(root,l,r);
	int mid = (l + r) >> 1;
	ll ans = 0;
	if (L <= mid)ans += querry(l, mid, L, R, root << 1);
	if (mid < R)ans += querry(mid + 1, r, L, R, root << 1 | 1);
	return ans;
}
void update(int l, int r, int L, int R, int root, ll val)
{
	if (L <= l && r <= R)
	{
		tree[root] = c[r] - c[l - 1] + (ll)(r - l + 1)*val;
		lazy[root] = val;
		return;
	}
//	cout << "l" << l << " r" << r << endl;
	pushdown(root, l, r);
	int mid = (l + r) >> 1;
	if (L <= mid)update(l, mid, L, R, root << 1, val);
	if (mid < R)update(mid + 1, r, L, R, root << 1 | 1, val);
	pushup(root);
}
int main()
{
	n = read();
	build(1, n, 1);
	upd(i, 2, n)
	{
		scanf("%lld", &b[i]);
		b[i] += b[i - 1];
	}
	upd(i, 2, n)
	{
		c[i] = c[i - 1] + b[i];
	}
	q = read();
	char s[2];
	int lf, rt;
	while (q--)
	{
		scanf("%s%d%d", s, &lf, &rt);
		if (s[0] == 's')
		{
			cout << querry(1, n, lf, rt, 1)<<endl;
		}
		else
		{
			ll va = querry(1, n, lf, lf, 1);
			int templf = lf-1;
			int temprt = n+1;
			while (temprt - 1 > templf)
			{
				int mid = (temprt + templf) >> 1;
			//	cout << "mid" << mid << endl;
				if (b[mid] - b[lf] + va + rt > querry(1, n, mid, mid, 1))templf = mid;
				else temprt = mid;
			}
			update(1, n, lf, templf, 1, va + rt - b[lf]);
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值