题意:你的攻击力为k,你优先攻击血量最多的怪物,血量相同击杀编号小的,问怪物被击杀的顺序,
思路:我们可以知道最后肯定存在一个状态,所有怪物就差一次攻击就死了,这个状态取决于其血量是否可以整除k,那么我们计算这种状态,排序一下就行
#include
using namespace std;
#define pi acos(-1)
#define xx first
#define yy second
#define endl "\n"
#define int long long
#define pb push_back
typedef pair PII;
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define Ysanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
const int N = 1e6 + 10, M = 1010, inf = 0x3f3f3f3f, mod = 998244353;
int n, k;
struct node
{
int x, id;
} a[N];
bool cmp(node a, node b)
{
if (a.x == b.x)
return a.id < b.id;
return a.x > b.x;
}
int ans[N];
void solve()
{
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; i++)
{
int xx;
cin >> xx;
if (xx % k != 0)
a[i].x = xx % k;
else
a[i].x = k;
a[i].id = i;
}
sort(a + 1, a + 1 + n, cmp);
for (int i = 1; i <= n; i++)
{
cout << a[i].id << " ";
}
cout << endl;
}
signed main()
{
Ysanqian;
int T;
// T = 1;
cin >> T;
while (T--)
solve();
return 0;
}
题意:给你一个01串,m个操作,每次给出左端点,右端点,将其左右端点之间的字符串排序
思路:对区间[ l , r ],如果区间已经有序等于没操作.
对于一个区间,显然前缀的0和后缀的1是没用的,所以我们只需找到第一个1的位置 l ′,最后一个0的位置 r ′,其实等价于给[l ′ , r ′]排序,拿个set维护以下这种等价类有多少种即可
思路转之知乎大佬
#include
using namespace std;
#define pi acos(-1)
#define X first
#define Y second
#define endl "\n"
#define int long long
#define pb push_back
typedef pair PII;
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define Ysanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
const int N = 1e6 + 10, M = 1 << 10, inf = 0x3f3f3f3f, mod = 998244353;
int n, m;
void solve()
{
string s;
set res;
cin >> n >> m;
cin >> s;
vector pre(n, -1), back(n, n); // 初始化就是把1111......000000这种情况解决了,这样就是无前缀0,无后缀1,相当于(-1~n)
for (int i = 0; i < n; i++) // 前缀0
{
if (i != 0)
pre[i] = pre[i - 1];
if (s[i] == '0')
pre[i] = i;
}
for (int i = n - 1; i >= 0; i--) // 后缀1,逆序前缀就行
{
if (i != n - 1)
back[i] = back[i + 1];
if (s[i] == '1')
back[i] = i;
}
for (int i = 1; i <= m; i++)
{
int l, r;
cin >> l >> r;
l--, r--;
int rr = pre[r], ll = back[l];
if (ll > rr)
res.insert({-1, -1});
else
res.insert({ll, rr});
}
cout << res.size() << endl;
}
signed main()
{
Ysanqian;
int T;
// T=1;
cin >> T;
while (T--)
solve();
}
题意:就是跟你一个0,1,2的全是蓝色的序列,让你通过两个操作使其全变为红色且花费最小,
1:花费一元,让一个数变为红色
2:让一个非0的红色元素值减1,选择它相邻的一个元素使其变红
思路:接贪心即可, 有 2 的话先操作 2 , 2 可以花费一元,向两侧扩展,可以使一个非零区间加上这个区间的两端的0,变为红色, 1 的话只能向 1 侧扩展,我们默认左传,它可以花费一让一个全一序列加上其左端的0为红,如果左端的没有0,我能让右端点的0变红,具体见代码注释
#include
using namespace std;
#define pi acos(-1)
#define xx first
#define yy second
#define endl "\n"
#define int long long
#define ull unsigned long long
#define pb push_back
typedef pair PII;
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define Ysanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
const int N = 1e6 + 10, M = 1010, inf = 1e11, mod = 998244353, P = 13331;
bool st[N];
int n;
void solve()
{
int ans = 0;
cin >> n;
vector a(n);
for (int i = 0; i < n; i++)
cin >> a[i];
for (int i = 0; i < n; i++)
{
if (a[i] == 0) // 如果是零我们直接跳过
continue;
int j = i, flag = 0;
while (j < n && a[j] != 0) // 如果不是是零我们就继续向后走直到再遇见0
{
if (a[j] == 2) // 如果再次过程中遇到2,标记一下,应为2可以花费一就可以使这一段全不为0的区间并且加上两端的两个0变为红色
flag = 1;
j++;
}
if (flag) // 标记两端的0变成红色了
{
st[i - 1] = st[j] = 1;
}
else // 如果没有2
{
if ((i - 1) >= 0 && !st[i - 1]) // 左端为0我们就让1的红色左穿即可
st[i - 1] = 1;
else // 反之右传
st[j] = 1;
}
ans++; // 我们一定用了一钱让2或1变红,因为只有非0点才可以到这
i = j - 1; // 跟新坐标点即可,我们最好将其跟新为j-1,或j,因为如果我们跟新更新成j+1的化,j这个0,就不能作为下一个2的左端点了
}
for (int i = 0; i < n; i++) // 看一下还有那些0点没有变红
if (a[i] == 0 && !st[i])
ans++;
cout << ans << endl;
}
signed main()
{
Ysanqian;
int T;
T = 1;
// cin >> T;
while (T--)
solve();
return 0;
}