直接输出2020+x即可。
对于第 i i i个点,它会与第 j j j个点 ( j ≠ i ) (j \ne i) (j=i)交换位置当且仅当两点连线的与线段 s t st st有交点。
所以对于每个询问,求出指定点与其他点与线段 s t st st的交点即可(如果有的话),如果交点个数小于 k i k_i ki,那么输出-1;
否则,按照每个交点与点 s s s的距离升序排序之后,输出第 k i k_i ki个交点的坐标即可。
一些小细节:
判断交点是否在线段 s t st st上,可以直接判断交点的横坐标是否在 s s s和 t t t中间
注意特殊处理垂直的线段
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 1005;
int n, m;
int xs, ys, xt, yt;
int x[N], y[N];
struct Node
{
double x, y;
double s;
bool operator < (const Node& b) const
{
return s < b.s;
}
}a[N];
double getk(double x1, double y1, double x2, double y2)
{
if (x1 == x2) return -1;
return 1.0 * (y1 - y2) / (x1 - x2);
}
double getb(double x, double y, double k)
{
return y - k * x;
}
double getdis(double x1, double y1, double x2, double y2)
{
double dx = x1 - x2, dy = y1 - y2;
return dx * dx + dy * dy;
}
void getPoint(double& X, double& Y, double k1, double b1, double k2, double b2)
{
if (k1 == k2){
X = Y = 1e18;
return;
}
if (k1 == -1.0)
{
X = b1;
Y = k2 * X + b2;
}
else if (k2 == -1.0)
{
X = b2;
Y = k1 * X + b1;
}
else
{
X = (b2 - b1) / (k1 - k2);
Y = k1 * X + b1;
}
}
int main()
{
#ifdef ZYCMH
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
#endif
scanf("%d%d", &n, &m);
scanf("%d%d%d%d", &xs, &ys, &xt, &yt);
for (int i = 1; i <= n; i ++ )
scanf("%d%d", &x[i], &y[i]);
double Kst = getk(xs, ys, xt, yt);
double Bst;
if (Kst != -1.0)
Bst = getb(xs, ys, Kst);
else Bst = xs;
for (int i = 1; i <= m; i ++ )
{
int hi, ki;
scanf("%d%d", &hi, &ki);
int xi = x[hi], yi = y[hi];
int cnt = 0;
for (int j = 1; j <= n; j ++ )
if (j != hi)
{
double K = getk(xi, yi, x[j], y[j]);
double B;
if (K != -1.0) B = getb(xi, yi, K);
else B = xi;
// printf("xi = %d yi = %d x[j] = %d y[j] = %d K = %.2f B = %.2f ", xi, yi, x[j], y[j], K, B);
double X, Y;
getPoint(X, Y, K, B, Kst, Bst);
// printf("X = %.2f Y = %.2f\n", X, Y);
if (min(xs, xt) <= X && X <= max(xs, xt))
a[++ cnt] = {X, Y, getdis(X, Y, xs, ys)};
}
if (cnt < ki)
puts("-1");
else
{
sort(a + 1, a + 1 + cnt);
printf("%.10f %.10f\n", a[ki].x, a[ki].y);
}
}
return 0;
}
分为下述三种情况:
1、如果排列已经有序,那么输出0
2、否则,如果对于每一个位置都有 i = = p [ p [ i ] ] i==p[p[i]] i==p[p[i]]的话,则一轮交换即可有序,即这一轮中的每一次交换都将无序的位置 i i i与位置 p [ i ] p[i] p[i]交换,不难证明这样交换不会出现重复的交换下标(因为无序的交换完就有序了,那么不会再被用去交换)
3、否则(存在 i ! = p [ p [ i ] ] i != p[p[i]] i!=p[p[i]]的位置),可以证明只需要两轮交换可以使原序列有序。第一轮交换一定可以把所有位置变为 i = = p [ p [ i ] ] i==p[p[i]] i==p[p[i]],第二轮交换同第二种情况。
那么如何在第一轮交换中把所有位置变为 i = = p [ p [ i ] ] i == p[p[i]] i==p[p[i]]。对于每一个 i ! = p [ p [ i ] ] i != p[p[i]] i!=p[p[i]]的位置,我们找到数字 i i i在原序列中的位置 p o s [ i ] pos[i] pos[i],交换位置 p o s [ i ] pos[i] pos[i]和位置 p [ i ] p[i] p[i]的数,此时位置 i i i已经满足 i = = p [ p [ i ] ] i == p[p[i]] i==p[p[i]],此时位置 p o s [ i ] pos[i] pos[i]不一定满足条件,于是需要继续往下考察,直到满足条件为止。(好难说清楚啊 自己手玩一下吧)
可以证明第一轮交换也是不会有下标冲突滴。
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 100005;
int n;
int p[N];
int pos[N];
bool check0()
{
for (int i = 1; i <= n; i ++ )
if (p[i] != i)
return false;
return true;
}
bool check1()
{
for (int i = 1; i <= n; i ++ )
if (p[p[i]] != i)
return false;
printf("1\n");
int cnt = 0;
for (int i = 1; i <= n; i ++ )
if (p[i] != i)
cnt ++;
printf("%d", cnt / 2);
for (int i = 1; i <= n; i ++ )
if (p[i] != i && i < p[i])
printf(" %d %d", i, p[i]);
puts("");
return true;
}
void solve()
{
printf("2\n");
vector<PII> ans;
for (int i = 1; i <= n; i ++ )
if (p[p[i]] != i)
{
int j = i;
while (p[p[j]] != j)
{
swap(p[pos[j]], p[p[j]]);
ans.push_back(make_pair(pos[j], p[j]));
j = pos[j];
}
}
printf("%d", (int)ans.size());
int sz = ans.size();
for (int i = 0; i < sz; i ++ )
printf(" %d %d", ans[i].first, ans[i].second);
puts("");
int cnt = 0;
for (int i = 1; i <= n; i ++ )
if (p[i] != i)
cnt ++;
printf("%d", cnt / 2);
for (int i = 1; i <= n; i ++ )
if (p[i] != i && i < p[i])
printf(" %d %d", i, p[i]);
puts("");
}
int main()
{
#ifdef ZYCMH
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
#endif
scanf("%d", &n);
for (int i = 1; i <= n; i ++ )
scanf("%d", &p[i]), pos[p[i]] = i;
if (check0())
{
puts("0");
return 0;
}
if (check1())
return 0;
solve();
return 0;
}
通过观察可以发现,一段下降子序列中,每两个点之间都有连边,那么这段子序列中每两个点的颜色都不能一样,于是所需要的总颜色数为最长下降子序列的长度。把每个点的颜色涂成以他结尾的最长下降子序列的长度即可。
最长下降子序列可以用二分或者树状数组求。
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 1000005;
int n;
int a[N];
int v[N];
int ans[N];
int main()
{
#ifdef ZYCMH
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
#endif
int _; scanf("%d", &_);
while (_ --)
{
scanf("%d", &n);
for (int i = 1; i <= n; i ++ )
scanf("%d", &a[i]), v[i] = 0;
v[0] = n + 1;
for (int i = 1; i <= n; i ++ )
{
int l = 0, r = n;
while (l < r)
{
int mid = (l + r + 1) / 2;
if (v[mid] > a[i])
l = mid;
else r = mid - 1;
}
ans[i] = l + 1;
v[l + 1] = max(v[l + 1], a[i]);
}
int res = 0;
for (int i = 1; i <= n; i ++ )
res = max(res, ans[i]);
printf("%d\n", res);
for (int i = 1; i <= n; i ++ )
{
if (i > 1) printf(" ");
printf("%d", ans[i]);
}
puts("");
}
return 0;
}
#include
using namespace std;
typedef long long LL;
const int N = 1000005, INF = 1e9;
int n, q;
int a[N];
int rt[N];
struct Tree
{
int l, r;
LL sum;
}t[N * 50];
int cnt;
int update(int i, int l, int r, int pos)
{
int p = ++ cnt;
t[p] = t[i];
t[p].sum += pos;
if (l == r)
return p;
int mid = (l + r) >> 1;
if (pos <= mid) t[p].l = update(t[i].l, l, mid, pos);
else t[p].r = update(t[i].r, mid + 1, r, pos);
return p;
}
LL query(int L_rt, int R_rt, int l, int r, int L, int R)
{
if (L <= l && r <= R) return t[R_rt].sum - t[L_rt].sum;
int mid = (l + r) >> 1;
LL s = 0;
if (L <= mid) s += query(t[L_rt].l, t[R_rt].l, l, mid, L, R);
if (R > mid) s += query(t[L_rt].r, t[R_rt].r, mid + 1, r, L, R);
return s;
}
int main()
{
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i ++ )
scanf("%d", &a[i]);
for (int i = 1; i <= n; i ++ )
rt[i] = update(rt[i - 1], 1, INF, a[i]);
LL last = 0;
for (int i = 1; i <= q; i ++ )
{
int l, r;
scanf("%d%d", &l, &r);
l = (l + last) % n + 1;
r = (r + last) % n + 1;
if (l > r) swap(l, r);
LL x = 0;
while (true)
{
LL t = query(rt[l - 1], rt[r], 1, INF, 1, min(1LL * INF, x + 1));
if (t == x) break;
x = t;
}
printf("%lld\n", x + 1);
last = x + 1;
}
return 0;
}