【题解】NOIP 13连测 #1
NOIP13连测 #1
A
首先根据数据范围判断时间复杂度为
,考虑排序。
常见 trik:把坐标轴旋转 45°,原本坐标变成 。
最大值为最接近或 ,从小排序后相邻的两个点最小值即为答案。
贪心!
-
40pts
一一枚举任意两个点,进行最大值的求解。 -
+40pts
假设两个点的横坐标和纵坐标之差分别为
当
当
- 100pts
给出结论,将所有点按
以下给出具体证明。
根据部分分的启发,容易发现两点连线和
我们把整个坐标轴旋转一下,原本点
那么问题就变成了找到两个点,它们和
#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9'){
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
#define rd rd()
void wt(int x){
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
wt(x / 10);
putchar(x % 10 + '0');
return;
}
void wt(char x){
putchar(x);
}
void wt(int x, char k){
wt(x),putchar(k);
}
namespace Star_F{
const int N = 100005;
int n;
PII a[N], p[N], q[N];
double dis1(int P, int Q) { return abs(a[P].fi - a[Q].fi) + abs(a[P].se - a[Q].se); }
double dis2(int P, int Q) {
return sqrt(1ll * (a[P].fi - a[Q].fi) * (a[P].fi - a[Q].fi) + 1ll * (a[P].se - a[Q].se) * (a[P].se - a[Q].se));
}
double ans = -1;
void Main(){
cin >> n;
for (int i = 1; i <= n;i++)
cin >> a[i].fi >> a[i].se;
for (int i = 1; i <= n;i++){
p[i] = {a[i].fi - a[i].se, i};
q[i] = {a[i].fi + a[i].se, i};
}
sort(p + 1, p + n + 1, [](PII a, PII b){ return a.fi < b.fi; });
sort(q + 1, q + n + 1, [](PII a, PII b){ return a.fi < b.fi; });
for (int i = 2; i <= n;i++){
double x = dis1(p[i - 1].se, p[i].se) / dis2(p[i - 1].se, p[i].se);
double y = dis1(q[i - 1].se, q[i].se) / dis2(q[i - 1].se, q[i].se);
ans = max({ans, x, y});
}
printf("%.15lf\n", ans);
ans=-1;
}
}
signed main(){
freopen("Apair.in","r",stdin);
freopen("Apair.out","w",stdout);
ClockA;
int T=1;
T=rd;
while(T--) Star_F::Main();
// ClockB;
return 0;
}
/*
* ▀▀▀██████▄▄▄ _______________
* ▄▄▄▄▄ █████████▄ / \
* ▀▀▀▀█████▌ ▀▐▄ ▀▐█ | Code has no BUG! |
* ▀▀█████▄▄ ▀██████▄██ | _________________/
* ▀▄▄▄▄▄ ▀▀█▄▀█════█▀ |/
* ▀▀▀▄ ▀▀███ ▀ ▄▄
* ▄███▀▀██▄████████▄ ▄▀▀▀▀▀▀█▌ ______________________________
* ██▀▄▄▄██▀▄███▀ ▀▀████ ▄██ █ \\
* ▄▀▀▀▄██▄▀▀▌████▒▒▒▒▒▒███ ▌▄▄▀▀▀▀█_____________________________ //
* ▌ ▐▀████▐███▒▒▒▒▒▐██▌
* ▀▄▄▄▄▀ ▀▀████▒▒▒▒▄██▀
* ▀▀█████████▀
* ▄▄██▀██████▀█
* ▄██▀ ▀▀▀ █
* ▄█ ▐▌
* ▄▄▄▄█▌ ▀█▄▄▄▄▀▀▄
* ▌ ▐ ▀▀▄▄▄▀
* ▀▀▄▄▀ ██
* \ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
* \- ▌ Name: Star_F ▀ ▀
* - ▌ (o) ▀
* /- ▌ Go Go Go ! ▀ ▀
* / ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
*/
B
构造题,先考虑特殊性质,再去推广
主要考察了构造的思想以及数论的相关内容。
30pts
通过搜索进行暴力求解。
+10pts
任意发现
+30pts
那么按照这个顺序,第一次操作取
100pts
我们把所有数按如下方式写出来。
其中矩阵的列为
以
因为
我们可以把每个点都和它右下角的那个点连接,例如操作
现在每条从左上到右下的斜线都已经联通了,我们需要把剩下的这些线连接在一起形成树。
注意到我们每次选择一个点和它正下方的那个点,把任意两条相邻的斜线连接,例如
那么按照这个顺序把所有相邻的斜线全部连接即可。
时间复杂度为
#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9'){
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
#define rd rd()
void wt(int x){
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
wt(x / 10);
putchar(x % 10 + '0');
return;
}
void wt(char x){
putchar(x);
}
void wt(int x, char k){
wt(x),putchar(k);
}
namespace Star_F{
int n, k, ne[2000005];
void Main(){
cin >> n >> k;
if(!(n&1)){
cout << -1 << endl;
return;
}
cout << n / 2 << endl;
int i, j, len = 1, tot, p = k, x, y;
while(p!=0)
p = (p + k) % n, len++;
tot = n / len;
for (i = 0; i < n;i++)
ne[i] = (i + k) % n;
if (tot == 1){
for (i = 1, x = 0; i < len; i += 2, x = ne[ne[x]])
cout << x << " " << ne[x] << endl;
return;
}
for (i = 0; i < tot - 1;i++)
for (j = 2,x = i, y = ne[i + 1]; j < len; j += 2, x = ne[ne[x]], y = ne[ne[y]])
cout << x << " " << y << endl;
for (i = 2, x = ne[0], y = ne[1]; i <= len; i += 2, x = ne[ne[x]], y = ne[ne[y]])
cout << x << " " << y << endl;
for (i = 1; i < tot; i += 2)
cout << i << " " << i + 1 << endl;
}
}
signed main(){
freopen("Btree.in","r",stdin);
freopen("Btree.out","w",stdout);
ClockA;
int T=1;
// T=rd;
while(T--) Star_F::Main();
// ClockB;
return 0;
}
/*
* ▀▀▀██████▄▄▄ _______________
* ▄▄▄▄▄ █████████▄ / \
* ▀▀▀▀█████▌ ▀▐▄ ▀▐█ | Code has no BUG! |
* ▀▀█████▄▄ ▀██████▄██ | _________________/
* ▀▄▄▄▄▄ ▀▀█▄▀█════█▀ |/
* ▀▀▀▄ ▀▀███ ▀ ▄▄
* ▄███▀▀██▄████████▄ ▄▀▀▀▀▀▀█▌ ______________________________
* ██▀▄▄▄██▀▄███▀ ▀▀████ ▄██ █ \\
* ▄▀▀▀▄██▄▀▀▌████▒▒▒▒▒▒███ ▌▄▄▀▀▀▀█_____________________________ //
* ▌ ▐▀████▐███▒▒▒▒▒▐██▌
* ▀▄▄▄▄▀ ▀▀████▒▒▒▒▄██▀
* ▀▀█████████▀
* ▄▄██▀██████▀█
* ▄██▀ ▀▀▀ █
* ▄█ ▐▌
* ▄▄▄▄█▌ ▀█▄▄▄▄▀▀▄
* ▌ ▐ ▀▀▄▄▄▀
* ▀▀▄▄▀ ██
* \ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
* \- ▌ Name: Star_F ▀ ▀
* - ▌ (o) ▀
* /- ▌ Go Go Go ! ▀ ▀
* / ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
*/
C
10pts
直接输出
20pts
通过爆搜,每次暴力枚举括号插入位置。
40pts
通过状态压缩DP,记录插入
70pts
容易发现,括号序列一共有
假如 (
为 )
为
现在考虑维护这些前缀和。
如果我们在当前序列某一位后插入一个 ()
,且那一位的前缀和为
同理可知,插入 )(
相当于把
我们观察到每次选中的数概率是均等的,所以我们并不关心数的顺序,只关心这个前缀和数组中每个数出现了多少次。
定义
有两种转移,第一种下一步变成了
第一种下一步变成了
最终答案即为
100pts
只需要将上面的 DP 过程优化即可,优化的思路很多,以下给出一种。
以第一种转移为例,引入辅助DP数组
相当于对于
#include <iostream>
#include <cstdio>
using namespace std;
#define int long long
const int N= 510;
const int mod = 998244353;
int n, X, Y, p, c[N[N], f[N][N], g[N][N];
inline int qpow(int x, int y) {
int res = 1;
for (; y; y >>= 1, x = x * x % mod)
if (y & 1)
res = res * x % mod;
return res;
}
void init_C() {
for (int i = 0; i <= n; i++) c[i][0] = 1;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= i; j++) c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}
void DP() {
for (int i = 0; i <= n; i++) f[0][i] = g[0][i] = 1;
for (int i = 1; i <= n; i++) {
for (int x = 0; x <= n; x++) {
for (int j = 0; j < i; j++)
f[i][x] = (f[i][x] + (p * f[j][x + 1] + (1 - p + mod) * (x ? f[j][x - 1] : 0)) % mod *
c[i - 1][j] % mod * g[i - j - 1][x] % mod) %
mod;
for (int j = 0; j <= i; j++)
g[i][x] = (g[i][x] + c[i][j] * f[j][x] % mod * f[i - j][x] % mod) % mod;
}
}
}
signed main() {
freopen("Cbracket.in", "r", stdin);
freopen("Cbracket.out", "w", stdout);
cin >> n >> X >> Y;
p = X * qpow(Y, mod - 2) % mod;
init_C();
DP();
int ans = f[n][0];
for (int i = 1; i <= 2 * n; i += 2) ans = ans * qpow(i, mod - 2) % mod;
cout << ans;
}
D
50pts
可以按如下方式进行DP,考虑
注意到
100pts
考虑可能的白魔法序列
因为
在原问题中,代价总和就等于
令
#include <bits/stdc++.h>
using namespace std;
#define x first
#define y second
#define mp(Tx, Ty) make_pair(Tx, Ty)
#define For(Ti, Ta, Tb) for (auto Ti = (Ta); Ti <= (Tb); Ti++)
#define Dec(Ti, Ta, Tb) for (auto Ti = (Ta); Ti >= (Tb); Ti--)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define range(Tx) begin(Tx), end(Tx)
const int N = 1e5 + 5;
long long a[N];
int n, t, fal[N], far[N];
void init(int n)
{
for (int i = 0; i <= n + 1; i++)
fal[i] = far[i] = i;
}
int find(int x, int fa[])
{
if (x == fa[x])
return x;
fa[x] = find(fa[x], fa);
return fa[x];
}
void U(int x, int y, int fa[]) { fa[find(y, fa)] = find(x, fa); }
int main(){
assert(freopen("Dmagic.in", "r", stdin));
assert(freopen("Dmagic.out", "w", stdout));
cin.tie(nullptr)->sync_with_stdio(false);
scanf("%d", &t);
while (t--)
{
memset(a, 0, sizeof(a));
scanf("%d", &n);
For(i, 1, n) scanf("%lld", &a[i]);
init(n);
a[0] = 3e9, a[n + 1] = 3e9;
long long tot = 6e9;
long long now = 0;
For(i, 0, n) now += abs(a[i + 1] - a[i]);
priority_queue<pair<int, pair<int, int>>, vector<pair<int, pair<int, int>>>, greater<pair<int, pair<int, int>>>> q;
For(i, 1, n) if (a[i] == a[i - 1]) U(i - 1, i, fal);
Dec(i, n, 1) if (a[i] == a[i + 1]) U(i + 1, i, far);
For(i, 1, n) if (find(i, fal) == i)
{
int l = i, r = find(i, far);
if (a[l - 1] > a[i] && a[r + 1] > a[i])
q.push(mp(r - l + 1, mp(min(a[l - 1] - a[i], a[r + 1] - a[i]), i)));
}
while (now > tot && !q.empty())
{
auto t = q.top();
q.pop();
int l = t.y.y, r = t.y.y + t.x - 1;
int minn = min(a[l - 1], a[r + 1]);
if (now - (minn - a[l]) * 2 < tot)
{
long long k = now - tot;
k = (k + 1) / 2;
a[l] = a[r] = a[l] + k;
break;
}
now = now - (minn - a[l]) * 2;
a[l] = a[r] = minn;
if (a[l] == a[l - 1])
U(l - 1, l, fal), U(l, l - 1, far);
if (a[r] == a[r + 1])
U(r + 1, r, far), U(r, r + 1, fal);
l = find(l, fal), r = find(r, far);
if (a[l - 1] > a[l] && a[r + 1] > a[r])
{
q.push(mp(r - l + 1, mp(min(a[l - 1] - a[l], a[r + 1] - a[r]), l)));
}
}
For(i, 1, n)
{
int father = find(i, fal);
a[i] = a[father];
}
long long ans = 0;
For(i, 1, n) ans += a[i];
printf("%lld\n", ans);
}
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 【.NET】调用本地 Deepseek 模型
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库