A. Replacing Elements(水贪心)
题意
思路
- 经过合理操作之后的数都小于等于 d,有两种情况可以:
- 本身数列所有的元素的都小于等于 d,这个时候不需要操作。。
- 数列中最小的两个数之和小于等于 d
代码
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <string>
#include <string>
#include <map>
#include <bitset>
#include <vector>
void fre() { system("clear"), freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { system("clear"), freopen("A.txt", "r", stdin);}
void Run(int x = 0) {
#ifdef ACM //宏定义免注释 freopen
if(! x) fre(); else Fre();
#endif
}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define db double
#define ll long long
#define ull unsigned long long
#define Pir pair<ll, ll>
#define m_p make_pair
#define for_(i, s, e) for(ll i = (ll)(s); i <= (ll)(e); i ++)
#define rep_(i, e, s) for(ll i = (ll)(e); i >= (ll)(s); i --)
#define memset(a, b, c) memset(a, (int)b, c);
#define size() size() * 1LL
#define sc scanf
#define pr printf
#define sd(a) scanf("%lld", &a)
#define ss(a) scanf("%s", a)
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define esp 1e-7
#define mod (ll)(1e9 + 7)
using namespace std;
/*=========================ACMer===========================*/
const ll mxn = 2e5 + 10;
ll ar[mxn];
int main()
{
Run();
ll T; sd(T);
while(T --)
{
ll n, d;
sc("%lld %lld", &n, &d);
for_(i, 1, n) sd(ar[i]);
sort(ar + 1, ar + 1 + n);
if(ar[1] + ar[2] <= d || ar[n] <= d)
pr("YES\n");
else
pr("NO\n");
}
return 0;
}
B. String LCM(思路)
题意
- 给两个仅由’a’、‘b’ 字符组成的字符串 u、v,问能不能找出一个最短的字符串 w,使 w 可以同时分别整除 u、v,
- 定义字符串乘法:字符串 x 数字 ,例如:abc x 2 = abcabc、ab x 3 = ababab
- 字符串 x 整除 y 的意思是:存在一个整数 c,使得 y * c = x。
- 如果存在输出最段的 w,否则输出 - 1。
思路
- 我们考虑如果存在一个 w 字符串,能同时整除 u、v 字符串,
- w 能整除 u,那么 w 的长度是 u 长度的倍数,
- w 能整除 v,那么 w 的长度是 v 长度的倍数,
- 所有 w 的长度是 u、v 长度的最小公倍数,这里设 u、v、w 的长度为 | u|、|v|、|w|,
那么$|w| = Lcm(|u|, |v|)$,
- 这个时候我们让我们
- 令 u ′ = u ∗ ∣ w ∣ / ∣ u ∣ u'=u*|w|/|u| u′=u∗∣w∣/∣u∣
- 令 v ′ = v ∗ ∣ w ∣ / ∣ v ∣ v'=v*|w|/|v| v′=v∗∣w∣/∣v∣
- 最后判读如果 u ′ = = v ′ u'==v' u′==v′ 的话,那么我们要求的 w 就是 u’或 v’,
- 否则输出 - 1。
代码
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <string>
#include <string>
#include <map>
#include <bitset>
#include <vector>
void fre() { system("clear"), freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { system("clear"), freopen("A.txt", "r", stdin);}
void Run(int x = 0) {
#ifdef ACM //宏定义免注释 freopen
if(! x) fre(); else Fre();
#endif
}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define db double
#define ll long long
#define ull unsigned long long
#define Pir pair<ll, ll>
#define m_p make_pair
#define for_(i, s, e) for(ll i = (ll)(s); i <= (ll)(e); i ++)
#define rep_(i, e, s) for(ll i = (ll)(e); i >= (ll)(s); i --)
#define memset(a, b, c) memset(a, (int)b, c);
#define size() size() * 1LL
#define sc scanf
#define pr printf
#define sd(a) scanf("%lld", &a)
#define ss(a) scanf("%s", a)
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define esp 1e-7
#define mod (ll)(1e9 + 7)
using namespace std;
/*=========================ACMer===========================*/
const ll mxn = 2e5 + 10;
ll ar[mxn];
ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
ll lcm(ll a, ll b) { return a * b / gcd(a, b); }
int main()
{
Run();
ll T; sd(T);
while(T --)
{
string a, b;
cin >> a >> b;
if(a.size() < b.size())
{
string t = a;
a = b;
b = t;
}
ll la = a.size();
ll lb = b.size();
ll n = lcm(la, lb);
string ta ="";
string tb ="";
for_(i, 1, n / la) ta += a;
for_(j, 1, n / lb) tb += b;
if(ta == tb)
{
cout << ta << endl;
}
else
pr("-1\n");
}
return 0;
}
C. No More Inversions(规律构造)
题意
- 给我们一个两个变量
n
、
k
(
k
<
=
n
<
2
∗
k
)
n、k(k<=n<2*k)
n、k(k<=n<2∗k),
注意这两个变量的取值限制关系
, - 现在有个一个 序列: a [ ] = { 1 , 2 , 3 , . . , k , k − 1 , . . , k − ( n − d ) } a[~]=\{1,2,3,..,k,k-1,..,k-(n-d)\} a[ ]={1,2,3,..,k,k−1,..,k−(n−d)},
- 让我们自己构造出一个 k 元全排列:p,
- 通过我们构造的这个全排列 p 我们可以求出来一个,序列 b [ ] = { p [ a [ 1 ] ] , p [ a [ 2 ] ] , . . . , p [ a [ n ] ] } b[~]=\{p[a[1]],p[a[2]],...,p[a[n]]\} b[ ]={p[a[1]],p[a[2]],...,p[a[n]]},
- 要求 b 中的逆序数的数量 <= a 中逆序数的数量,在 b 字典尽量大的前提下,
- 让我们输出这个的构造的 p,
这里注意题目说符合题意的 p 是唯一的
- 注意:数组下标从均从 1 开始
思路
- 这题我是找规律做出的来的,
- 首先我们观察序列: a [ ] = { 1 , 2 , 3 , . . , k , k − 1 , . . , k − ( n − d ) } a[~]=\{1,2,3,..,k,k-1,..,k-(n-d)\} a[ ]={1,2,3,..,k,k−1,..,k−(n−d)},后半部分存在对称的部分为: k , . . . , k + 1 , k + 2 , k , k − 1 , k − 2 , . . , k − ( n − d ) {k,...,k+1,k+2,k,k-1,k-2,..,k-(n-d)} k,...,k+1,k+2,k,k−1,k−2,..,k−(n−d), 关于 k 对称,两边元素的值向外逐渐递减,
- 那么因为:a 存在对称,那么无论 p 是什么样的排列,根据的序列 b 的定义, b [ ] = { p [ a [ 1 ] ] , p [ a [ 2 ] ] , . . . , p [ a [ n ] ] } b[~]=\{p[a[1]],p[a[2]],...,p[a[n]]\} b[ ]={p[a[1]],p[a[2]],...,p[a[n]]}, 那么 b 必定也是存在部分对称的情况,
- 那么的
- b 的对称部分为: p [ 2 ∗ k − n ] , . . . p [ k − 2 ] , p [ k − 1 ] , p [ k ] , p [ k − 1 ] , p [ k − 2 ] , . . , p [ 2 ∗ k − n ] {~~p[2*k-n],...~~p[k-2],~~p[k-1],~~p[k],~~p[k-1],~~p[k-2],..,~~p[2*k-n]} p[2∗k−n],... p[k−2], p[k−1], p[k], p[k−1], p[k−2],.., p[2∗k−n]
- 那么 b 不对称部分为: p [ a [ 1 ] ] , p [ a [ 2 ] ] , . . . , p [ a [ 2 ∗ k − n − 1 ] ] p[a[1]],~~p[a[2]],...,p[a[2*k-n-1]] p[a[1]], p[a[2]],...,p[a[2∗k−n−1]]
- 找规律发现:如果我得出的 b,要想最优的话,
- 那么 b 的不对称部分保持不变,仍然为: p [ a [ 1 ] ] , p [ a [ 2 ] ] , . . . , p [ a [ 2 ∗ k − n − 1 ] ] p[a[1]],~~p[a[2]],...,p[a[2*k-n-1]] p[a[1]], p[a[2]],...,p[a[2∗k−n−1]]
- 对称部分变为: p [ k ] , p [ k − 1 ] , . . . , p [ 2 ∗ k − n ] , . . . , p [ k − 1 ] , p [ k ] p[k],p[k-1],...,p[2*k-n],...,p[k-1],p[k] p[k],p[k−1],...,p[2∗k−n],...,p[k−1],p[k],
- 我们通过最优的 b 的构造出,从而反推出的 p,具体 p 的构造直接看代码把,,
- 有想证明的大佬自行证明一下吧,
代码
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <string>
#include <string>
#include <map>
#include <bitset>
#include <vector>
void fre() { system("clear"), freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { system("clear"), freopen("A.txt", "r", stdin);}
void Run(int x = 0) {
#ifdef ACM //宏定义免注释 freopen
if(! x) fre(); else Fre();
#endif
}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define db double
#define ll long long
#define ull unsigned long long
#define Pir pair<ll, ll>
#define m_p make_pair
#define for_(i, s, e) for(ll i = (ll)(s); i <= (ll)(e); i ++)
#define rep_(i, e, s) for(ll i = (ll)(e); i >= (ll)(s); i --)
#define memset(a, b, c) memset(a, (int)b, c);
#define size() size() * 1LL
#define sc scanf
#define pr printf
#define sd(a) scanf("%lld", &a)
#define ss(a) scanf("%s", a)
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define esp 1e-7
#define mod (ll)(1e9 + 7)
using namespace std;
/*=========================ACMer===========================*/
const ll mxn = 2e5 + 10;
ll ar[mxn];
ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
ll lcm(ll a, ll b) { return a * b / gcd(a, b); }
int main()
{
Run();
ll T; sd(T);
while(T --)
{
ll n, k;
sc("%lld %lld", &n, &k);
ll d = n - k + 1;
for_(i, 1, k - d) pr("%lld ", i);
rep_(i, k, k - d + 1) pr("%lld ", i);
pr("\n");
}
return 0;
}
D. Program(维护)
题意
-
给我们一个长度为 n 仅由 +、- 字符组成的字符串 s,有一个变量 x 的初始值为 0,
- '+' 代表:令 x+=1,
- '-' 代表:令 x-=1
-
又给我们了 m 次操作,每次操作给一个区间 [l, r], 意思是如果把这个 s 中位于 [l,r] 区间内的字符舍弃,其他字符的相对位置不变的话形成 s’,求出从 s’ 第一个字符,到最后一个字符一次执行相应位置的字符所代表的操作,问会有多少个不同的 x 产生,在执行操作期间,
思路
- 我们先不考虑从 s 中删除的一个子串,考虑执行 s 这个命令字符串,会产生多少个不同的 x,看下面执行 s 时候 x 的值的变化图,可以得出的 x 的不同的值数量为区间的最大值与最小值之差在加上 + 1。
- 先我们有了删除 s 中的某个子串,形成 s’(如上图绿色部分的操作),让后让求 s’所能产生的不同 x 的数量,那么我们可以维护前缀的最大最小值,和后缀的最大最小值,
- 前缀的最大最小值直接维护就可以得到,
for_(i, 1, n) //维护前缀最大、最小值
{
if(s[i] == '+') now += 1;
if(s[i] == '-') now -= 1;
mx = max(mx, now);
mn = min(mn, now);
seg1[i] = (Node){ mx, mn, now };
}
- 后缀的最大、最小值,
mx = mn = now = 0;
rep_(i, n, 1) //从后往前维护以 i 为起点的最大、最小值
{
if(s[i] == '+') now += 1;
if(s[i] == '-') now -= 1;
mx = max(mx, now);
mn = min(mn, now);
seg2[i] = (Node){ now - mn, now - mx, 0 };
}
//这里解释一下为什么?以 i 为起点的最大值是 now - mn,
//首先我们要确定 now 对于 i 这个位置是一个定值,
//而 mn 是 j 位置(j>=i)的一个son最小值,从 j 位置的 son 转移到 i 位置的 son 必定是拥有相对'+' 号操作最多的哪段,(感性理解一下就是 从一个 数字 a 变成一个数字 b,那么 a 越小那么,a 变成 b 就需要的+1 操作越多,那么就是'+'操作越多!!!)
代码
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <string>
#include <string>
#include <map>
#include <bitset>
#include <vector>
void fre() { system("clear"), freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { system("clear"), freopen("A.txt", "r", stdin);}
void Run(int x = 0) {
#ifdef ACM //宏定义免注释 freopen
if(! x) fre(); else Fre();
#endif
}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define db double
#define ll long long
#define ull unsigned long long
#define Pir pair<ll, ll>
#define m_p make_pair
#define for_(i, s, e) for(ll i = (ll)(s); i <= (ll)(e); i ++)
#define rep_(i, e, s) for(ll i = (ll)(e); i >= (ll)(s); i --)
#define memset(a, b, c) memset(a, (int)b, c);
#define size() size() * 1LL
#define sc scanf
#define pr printf
#define sd(a) scanf("%lld", &a)
#define ss(a) scanf("%s", a)
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define esp 1e-7
#define mod (ll)(1e9 + 7)
using namespace std;
/*=========================ACMer===========================*/
const ll mxn = 2e5 + 10;
struct Node
{
ll mx, mn, now;
} seg1[mxn], seg2[mxn];
char s[mxn];
int main()
{
Run();
ll T; sd(T);
while(T --)
{
ll n, m;
sc("%lld %lld", &n, &m);
ss(s + 1);
ll mx = 0, mn = 0, now = 0;
for_(i, 1, n) //维护前缀最大、最小值
{
if(s[i] == '+') now += 1;
if(s[i] == '-') now -= 1;
mx = max(mx, now);
mn = min(mn, now);
seg1[i] = (Node){ mx, mn, now };
}
mx = mn = now = 0;
rep_(i, n, 1) //从后往前维护以 i 为起点的最大、最小值
{
if(s[i] == '+') now += 1;
if(s[i] == '-') now -= 1;
mx = max(mx, now);
mn = min(mn, now);
seg2[i] = (Node){ now - mn, now - mx, 0 };
}
seg1[0] = seg2[n + 1] = (Node){ 0, 0, 0 }; //特殊处理一下边界,防止越界问题
ll l, r;
while(m --)
{
sc("%lld %lld", &l, &r);
ll maxx = max(seg1[l - 1].mx, seg1[l - 1].now + seg2[r + 1].mx);
ll minn = min(seg1[l - 1].mn, seg1[l - 1].now + seg2[r + 1].mn);
ll ans = maxx - minn + 1;
pr("%lld\n", ans);
}
}
return 0;
}