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;
}