A:题目大意:有三个怪物血量a,b,c 每回合可以对一个怪物造成一点伤害,每7回合对三个怪物都造成一点伤害,问是否能够在某一回合同时击杀三个怪物。
每7个回合总共造成9点伤害,由此可以求出总的回合数,只需要看最小的是否小于回合数即可
B:题目大意:你有一个序列a,希望构造一个序列b,使得b满足
1.bi在1~1e9范围内
2.bi和bi+1能够整除
3.2 * |ai - bi| <= S S为a中元素的和
观察到前面的系数2,所以考虑用2的倍数来构造
对于任意一个数都在连续的2的幂次中间,即2 ^ i <= aj <= 2 ^ (i + 1),每次选取靠近x的那边,可以证明每次选取的值ai, bi做差之后的绝对值均小于等于x / 2
如此构造即可,注意上界1e9的条件,特殊判断一下2 ^ 29 - 2 ^ 30的情况
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define db double
using namespace std;
int read() {
int rt = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <='9') {
rt = (rt << 3) + (rt << 1) + ch - '0';
ch = getchar();
}
return rt * f;
}
const int maxn = 55;
int mi[32];
int T, n, a[maxn], b[maxn];
int main() {
T = read();
mi[0] = 1;
for (int i = 1; i <= 30; i++) mi[i] = mi[i - 1] << 1;
while (T--) {
n = read();
for (int i = 1; i <= n; i++) a[i] = read();
for (int i = 1; i <= n; i++) {
int pos;
for (int j = 0; j <= 30; j++) {
if (mi[j] <= a[i] && mi[j + 1] > a[i]) {
pos = j;
break;
}
}
if (pos == 29) {
b[i] = mi[pos];
continue;
}
int tmp1 = a[i] - mi[pos];
int tmp2 = mi[pos + 1] - a[i];
if (tmp1 <= tmp2) b[i] = mi[pos];
else b[i] = mi[pos + 1];
}
for (int i = 1; i <= n; i++) printf("%d ", b[i]);
puts("");
}
return 0;
}
/*
8
3
1 5
3 0
6 4
3
1 5
2 4
10 -5
1
5
2 -5
3 1
4 1
5 1
6 1
4
3 3
5 -3
9 2
12 0
8
1 1
2 -6
7 2
8 3
12 -9
14 2
18 -1
23 9
5
1 -4
4 -7
6 -1
7 -3
8 -7
2
1 2
2 -2
6
3 10
5 5
8 0
12 -4
14 -7
19 -5
1
3
0 2
2 2
2 5
*/
C:题目大意:
你有一个机器人,这个机器人在一维坐标轴上移动。你可以给这个机器人下达指令,指令的形式为 ti,xi ,意味着机器人在第ti秒的时候获得一条指令,此时这个机器人以1/s的速度从现在的位置开始向xixi移动。若机器人执行当前指令的过程中收到其他命令,那么其他命令会被忽略。
现在问你给出的指令中被成功执行的命令有几条,被成功执行的命令的定义并不是字面意义上的成功之行,题目给出的成功之行命令的条件为:
假设当前命令为 ti,xi , 若机器人在 ti到 ti+1这个时间区间(包括边界)内到达过 xi 这个位置,则称这条命令被成功执行。
对于最后一条命令 tn,xn,我们认为有一个tn+1=∞ 。
考虑进行模拟
每个点的答案只会在ti -ti+1这段时间更新,所以模拟每段时间发生的事情。
考虑记录一下每次前进的方向和时间
两种情况
1.到下一个t的时候,原来前进还没有结束
2.在中间或者末尾的时候结束了
对于这两种情况,机器人在这个事件段内的活动都是单调的,可以找出对应的活动范围L-R
对于1的情况 行动时间对应减少就可以了
对于2的情况,更新行动的方向和时间
模拟完即可
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define db double
using namespace std;
ll read() {
ll rt = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <='9') {
rt = (rt << 3) + (rt << 1) + ch - '0';
ch = getchar();
}
return rt * f;
}
const int maxn = 1e5 + 5;
ll T, a, b, c, n, t[maxn], x[maxn];
int main() {
T = read();
while (T--) {
n = read();
for (int i = 1; i <= n; i++) t[i] = read(), x[i] = read();
ll d, tim;
ll pos = 0;
if (x[1] > 0) d = 1, tim = x[1];
else if (x[1] == 0) d = 0, tim = 0;
else d = -1, tim = -x[1];
t[n + 1] = 1e14;
ll ans = 0;
for (int i = 2; i <= n + 1; i++) {
if (t[i] - t[i - 1] >= tim) {
ll tmp = pos + d * tim;
ll L = min(tmp, pos);
ll R = max(tmp, pos);
if (x[i - 1] >= L && x[i - 1] <= R) ans++;
pos = tmp;
if (x[i] > pos) d = 1, tim = (x[i] - pos);
else if (x[i] == pos) d = 0, tim = 0;
else d = -1, tim = (pos - x[i]);
} else {
ll tmp = pos + d * (t[i] - t[i - 1]);
ll L = min(tmp, pos);
ll R = max(tmp, pos);
if (x[i - 1] >= L && x[i - 1] <= R) ans++;
pos = tmp;
tim -= (t[i] - t[i - 1]);
}
}
printf("%lld\n", ans);
}
return 0;
}
/*
8
3
1 5
3 0
6 4
3
1 5
2 4
10 -5
1
5
2 -5
3 1
4 1
5 1
6 1
4
3 3
5 -3
9 2
12 0
8
1 1
2 -6
7 2
8 3
12 -9
14 2
18 -1
23 9
5
1 -4
4 -7
6 -1
7 -3
8 -7
2
1 2
2 -2
6
3 10
5 5
8 0
12 -4
14 -7
19 -5
1
3
0 2
2 2
2 5
*/
D:题目大意:有一个2n的排列组成了n对,n对中有x对选了小的值,有n-x选了大的值,给出一个选择后的序列,问可能的x共有多少种
将排列分为两部分,一部分是最终答案,一部分是拿来配对的。
考虑x的最小最大值
x取最小的时候,即对于选择后的序列中的元素优先考虑比他小的数拿来配对
这种情况要分类,类似于田忌赛马那样的贪心
维护双指针
如果配对序列中的最小值已经不能满足了,那就去搞掉最大值
如果可以满足条件就配对
x取最大值的时候,优先考虑比他大的数拿来配对
这种情况按顺序排好之后对应配对就可以了
现在求出了最小最大值,由于交换两个数的位置,最多对答案的产生1的贡献,那么最小最大值都可以取到,那么总的可能就是最小到最大值中的所有值。
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<set>
#define ll long long
#define db double
using namespace std;
int read() {
int rt = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <='9') {
rt = (rt << 3) + (rt << 1) + ch - '0';
ch = getchar();
}
return rt * f;
}
const int maxn = 2e5 + 5;
int T, n, b[maxn], a[maxn], cnt;
bool vis[maxn << 1];
int main() {
T = read();
while (T--) {
n = read();
cnt = 0;
for (int i = 1; i <= 2 * n; i++) vis[i] = 0;
for (int i = 1; i <= n; i++) b[i] = read(), vis[b[i]] = 1;
for (int i = 1; i <= 2 * n; i++) {
if (!vis[i]) a[++cnt] = i;
}
int lf = 1, ma = 0, mi = 0, rg = n;
for (int i = 1; i <= n; i++) {
while (lf <= rg && a[lf] < b[i]) lf++;
if (lf > rg) break;
ma++;
lf++;
}
lf = 1;
rg = n;
for (int i = 1; i <= n; i++) {
if (lf > rg) break;
if (b[i] < a[lf]) {
mi++;
rg--;
} else {
lf++;
}
}
printf("%d\n", ma - mi + 1);
}
return 0;
}
/*
8
3
1 5
3 0
6 4
3
1 5
2 4
10 -5
1
5
2 -5
3 1
4 1
5 1
6 1
4
3 3
5 -3
9 2
12 0
8
1 1
2 -6
7 2
8 3
12 -9
14 2
18 -1
23 9
5
1 -4
4 -7
6 -1
7 -3
8 -7
2
1 2
2 -2
6
3 10
5 5
8 0
12 -4
14 -7
19 -5
1
3
0 2
2 2
2 5
*/
E:题目大意:有许多约束条件,有些是大致的大小关系,有些必须相邻,问是否存在一种合法排列并输出
首先考虑不合法情况,即中间成环的情况
剩下考虑如何解决相邻
既然已经相邻那么缩点就可以了
最后跑topsort来得到答案
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<unordered_map>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=1e6+100;
int p[N],f[N],nt[N],c[N],ord[N],ban[N],du[N],id;
vector<int>node[N],dcc[N],ans;
int find(int x)
{
return f[x]==x?x:f[x]=find(f[x]);
}
void merge(int x,int y)//y->x
{
int xx=find(x),yy=find(y);
if(xx!=yy)
f[yy]=xx;
}
int topo(int st)
{
int cnt=0;
queue<int>q;
q.push(st);
while(q.size())
{
int u=q.front();
q.pop();
cnt++;
for(auto it:dcc[u])
ans.push_back(it);
for(auto v:node[u])
if(--du[v]==0)
q.push(v);
}
return cnt;
}
int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.in.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
int n,m,rt;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",p+i);
if(p[i]==0)
rt=i;
}
for(int i=1;i<=m;i++)//并查集缩点
{
int u,v;
scanf("%d%d",&u,&v);
nt[u]=v;
ban[v]=true;//v被缩到u的集合中去,在新图中相当于被ban掉了
merge(u,v);
}
for(int i=1;i<=n;i++)//缩点
{
if(ban[i])
continue;
id++;
int pos=i;
while(pos&&!c[pos])//注意这里会出现环的情况
{
ord[pos]=dcc[id].size();
dcc[id].push_back(pos);
c[pos]=id;
pos=nt[pos];
}
}
for(int i=1;i<=n;i++)//如果拓扑存在环的话,就不会被遍历到
if(!c[i])
return 0*puts("0");
for(int i=1;i<=n;i++)//建边
{
if(i==rt)
continue;
if(c[i]!=c[p[i]])
{
node[c[p[i]]].push_back(c[i]);
du[c[i]]++;
}
else if(ord[p[i]]>ord[i])//特判
return 0*puts("0");
}
if(topo(c[rt])!=id)//拓扑中有环
return 0*puts("0");
for(auto it:ans)
printf("%d ",it);
puts("");
return 0;
}