暑假集训三[数列,数对,最小距离, 真相]
作者:互联网
暑假集训3
数列
好在这个题是单点操作,所以我们保证每一个点的\(opt\)最小就行
-
所以相当于去求一个
-
\(\large ax + by\equiv wmx[i] (mod\ \ gcd(a, b))\)
并且保证\(\large abs(x) + abs(y)\)最小(\(x, y\)可以为负),所以,很显然的扩欧
(然鹅扩欧不会写就没救了,可以看看青蛙的约会)
对于\(x = 1\)的情况能用扩欧简单地解出来 -
因为\(\large ax \equiv 1(mod\ \ b)\)可以化为
\(\large ax - 1 = bz\ \ z\in \mathbb{z}\)(同余的定义)所以可以转成解方程 -
我们考虑已知\( \large ax + by = z\)
那么可以得到
\(\large ax + kab + by - kab = z\)
所以现在的解集为
\(\large (x + kb, y - ka)\)
我们只需要让\(x\)趋近于\(0\)或者\(y\)趋近于\(0\)就行 \(->\)即是找最大的负值或者最小的正值 -
已知一个方程, 解其他的方程
直接两边同乘(\(tmp / gcd\)即可)为了找特解,但不一定是最优接,所以还得判
here
#include <bits/stdc++.h>
#define LL long long
#define Re register int
#define LD long double
#define mes(x, y) memset(x, y, sizeof(x))
#define cpt(x, y) memcpy(x, y, sizeof(x))
#define fuc(x, y) inline x y
#define fr(x, y, z)for(Re x = y; x <= z; x ++)
#define fp(x, y, z)for(Re x = y; x >= z; x --)
#define frein(x) freopen(#x ".in", "r", stdin)
#define freout(x) freopen(#x ".out", "w", stdout)
#define ki putchar('\n')
#define fk putchar(' ')
#define WMX aiaiaiai~~
#define pr pair<long long, long long>
#define mk(x, y) make_pair(x, y)
using namespace std;
namespace kiritokazuto{
auto read = [](){
LL x = 0;
int f = 1;
char c;
while (!isdigit(c = getchar())){ if (c == '-')f = -1; }
do{ x = (x << 1) + (x << 3) + (c ^ 48); } while (isdigit(c = getchar()));
return x * f;
};
template <typename T> fuc(void, write)(T x){
if (x < 0)putchar('-'), x = -x;
if (x > 9)write(x / 10); putchar(x % 10 | '0');
}
}
using namespace kiritokazuto;
const int maxn = 1e3 + 10, Mod = 1e9 + 7;
const int Inf = 2147483647;
// int wmx[maxn];
/*
她在夜里穿过我梦中的湖,在它的岸边,我看见过诸神漫步,而从湖心深处,我的魔法城堡升起。她踩着梦幻阶梯,闯入我的不夜城
*/
LL a, b, c;
LL n;
LL lstx, lsty;
LL d, y, ans;
// LL gcd;
fuc(LL, ex_gcd)(LL a, LL b){
if (!b){
lstx = 1, y = 0;
return a;
}
LL tmp = ex_gcd(b, a % b);
LL res = lstx;
lstx = lsty;
lsty = res - a / b * lsty;
return tmp;
}
signed main(){
n = read();
a = read();
b = read();
if (a > b) swap(a, b);
LL tmp = ex_gcd(a, b);
//求出x = 1的特解
// write(lstx);
LL res1 = b / tmp;
LL res2 = a / tmp;
fr(i, 1, n){
LL x = read();
if(x < 0)x = -x;
if (x % tmp){
write(-1);
return 0;
}
LL tpx = (x / tmp * lstx % res1 + res1) % res1;
LL tpy = (x - a * tpx) / b;
if (abs(tpx - res1) + abs(tpy + res2) < abs(tpx) + abs(tpy)){
tpx -= res1;
tpy += res2;
}
ans += abs(tpx) + abs(tpy);
}
write(ans);
return 0;
}
数对
这个题的\(dp\)其实很好想,就是忘记优化了..赛时忘记开\(long long\)苟掉了\(40pts\)其实还可以滚掉一维,但没必要..
-
首先它选,那么为了跑\(dp\),我们得保证选出来的是合法的所以假设为\(i和j\),我们要让\(i\)必须在\(j\)之前,贪心都要选,所以此时应该保证
\(\large a_i < b_j\) 以及 \(\large b_i < a_j\)
第二个不等式是保证\(j\)不会在\(i\)前被选
-
所以可以得到\(cmp\)函数
\(\large a_i + b_i < a_j + b_j\)
但是当$$\large a_i + b_i == a_j + b_j$$
时,应当让\(a\)升序排,保证不会过早出现\(a_i < b_j\)的情况 -
其次本题离散化是应为\(dp\)的定义需要用到值域的下标...
-
定义\(\large dp[i][j]\)表示排好序的序列中选前i个数,其中最大的\(a\)值等于\(j\)的最大权值和
-
那么很
显然可以得到\(dp\)转移柿子-
当\(b_i < a_i\)时
\(\large dp[i][a] = Max_{i = 1} ^ {b_i}dp[i - 1][j] + w_i\)
(现在显然最大值是\(a_i\)因为我是循环的,同时前边合法的\(a\)是都不能超过\(b_i\)的)
-
当\(b_i > a_i\) 时
\(\large dp[i][a] = Max_{i = 1} ^ {a_i}dp[i - 1][j] + w_i\)
(同理)
\(\large dp[i][j] = Max_{i = a_i + 1} ^ {b_i}dp[i - 1][j] + w_i\)
(最大值比\(a_i\)还大的)
-
当然还有一个初值
\(\large dp[i][j] = dp[i - 1][j] i \in [1, n]\ \ j \in [1, cnt]\)
(最大值不变,\(cnt\)为离散化之后的长度)
-
-
之后就是把这玩意在线段树上维护一下就行,单点修改,区间查询,区间修改
无优化
#include <bits/stdc++.h>
#define LL long long
#define Re register int
#define LD long double
#define mes(x, y) memset(x, y, sizeof(x))
#define cpt(x, y) memcpy(x, y, sizeof(x))
#define fuc(x, y) inline x y
#define fr(x, y, z)for(Re x = y; x <= z; x ++)
#define fp(x, y, z)for(Re x = y; x >= z; x --)
#define frein(x) freopen(#x ".in", "r", stdin)
#define freout(x) freopen(#x ".out", "w", stdout)
#define ki putchar('\n')
#define fk putchar(' ')
#define WMX aiaiaiai~~
#define pr pair<long long, long long>
#define mk(x, y) make_pair(x, y)
using namespace std;
namespace kiritokazuto{
auto read = [](){
LL x = 0;
int f = 1;
char c;
while (!isdigit(c = getchar())){ if (c == '-')f = -1; }
do{ x = (x << 1) + (x << 3) + (c ^ 48); } while (isdigit(c = getchar()));
return x * f;
};
template <typename T> fuc(void, write)(T x){
if (x < 0)putchar('-'), x = -x;
if (x > 9)write(x / 10); putchar(x % 10 | '0');
}
}
using namespace kiritokazuto;
const int maxn = 1e4 + 10, Mod = 1e9 + 7;
const int Inf = 2147483647;
/*
她在夜里穿过我梦中的湖,在它的岸边,我看见过诸神漫步,而从湖心深处,我的魔法城堡升起。
*/
LL n, ans;
LL dp[3001][80100];//前i个数中,maxa = j的最大权值和
LL cnt, lsh[200010];
struct Thisisapairwithw{
LL a, b;
LL w;
}wmx[3010];
fuc(bool, cmp)(Thisisapairwithw A, Thisisapairwithw B){
return (A.a + A.b == B.a + B.b) ? (A.a < B.a) : A.a + A.b < B.a + B.b;
/*
如果一个ai < bj 那么当bi也 < aj时应该是更加优秀的
否则他俩互相放换地方没啥意思
*/
}
fuc(LL, maxx)(LL x, LL y){ return (x > y) ? x : y; }
signed main(){
// frein(in);
//freout(outttt);
n = read();
fr(i, 1, n){
lsh[++cnt] = wmx[i].a = read();
lsh[++cnt] = wmx[i].b = read();
wmx[i].w = read();
}
sort(wmx + 1, wmx + n + 1, cmp);
// fr(i, 1, n){
// printf("true : wmx[%d].a = %d wmx[%d].b = %d\n", i, wmx[i].a, i, wmx[i].b);
// }
// ki;
sort(lsh + 1, lsh + cnt + 1);
cnt = unique(lsh + 1, lsh + cnt + 1) - lsh - 1;
fr(i, 1, n){
wmx[i].a = lower_bound(lsh + 1, lsh + cnt + 1, wmx[i].a) - lsh;
wmx[i].b = lower_bound(lsh + 1, lsh + cnt + 1, wmx[i].b) - lsh;
}
// fr(i, 1, n){
// printf("wmx[%d].a = %d wmx[%d].b = %d\n", i, wmx[i].a, i, wmx[i].b);
// }
fr(i, 1, n){
fr(j, 1, cnt)dp[i][j] = dp[i - 1][j];
LL len = min(wmx[i].a, wmx[i].b);
LL a = wmx[i].a;
LL b = wmx[i].b;
LL w = wmx[i].w;
fr(j, 1, len){
dp[i][a] = maxx(dp[i][a], dp[i - 1][j] + w);
// printf("1 == dp[%d][%d] = %d \n", i, j, dp[i][j]);
}
fr(j, a + 1, b){
dp[i][j] = maxx(dp[i][j], dp[i - 1][j] + w);
// printf("2 == dp[%d][%d] = %d \n", i, j, dp[i][j]);
}
}
fr(i, 1, n){
fr(j, 1, cnt){
ans = maxx(dp[i][j], ans);
}
}
write(ans);
return 0;
}
Seg_tree
#include <bits/stdc++.h>
#define LL long long
#define Re register int
#define LD long double
#define mes(x, y) memset(x, y, sizeof(x))
#define cpt(x, y) memcpy(x, y, sizeof(x))
#define fuc(x, y) inline x y
#define fr(x, y, z)for(Re x = y; x <= z; x ++)
#define fp(x, y, z)for(Re x = y; x >= z; x --)
#define frein(x) freopen(#x ".in", "r", stdin)
#define freout(x) freopen(#x ".out", "w", stdout)
#define ki putchar('\n')
#define fk putchar(' ')
#define WMX aiaiaiai~~
#define pr pair<long long, long long>
#define mk(x, y) make_pair(x, y)
using namespace std;
namespace kiritokazuto{
auto read = [](){
LL x = 0;
int f = 1;
char c;
while (!isdigit(c = getchar())){ if (c == '-')f = -1; }
do{ x = (x << 1) + (x << 3) + (c ^ 48); } while (isdigit(c = getchar()));
return x * f;
};
template <typename T> fuc(void, write)(T x){
if (x < 0)putchar('-'), x = -x;
if (x > 9)write(x / 10); putchar(x % 10 | '0');
}
}
using namespace kiritokazuto;
const int maxn = 4e5 + 10, Mod = 1e9 + 7;
const int Inf = 2147483647;
#define int long long
/*
她在夜里穿过我梦中的湖,在它的岸边,我看见过诸神漫步,而从湖心深处,我的魔法城堡升起。
*/
#define lsp (rt << 1)
#define rsp (rt << 1 | 1)
LL n, ans;
LL cnt, lsh[maxn];
struct Thisisapairwithw{
LL a, b;
LL w;
}wmx[maxn];
fuc(bool, cmp)(Thisisapairwithw A, Thisisapairwithw B){
return (A.a + A.b == B.a + B.b) ? (A.a < B.a) : A.a + A.b < B.a + B.b;
/*
如果一个ai < bj 那么当bi也 < aj时应该是更加优秀的
否则他俩互相放换地方没啥意思
*/
}
fuc(LL, maxx)(LL x, LL y){ return (x > y) ? x : y; }
fuc(LL, minn)(LL x, LL y){ return (x > y) ? y : x; }
LL lazy[maxn];
struct Node{
LL lazy;
LL Max;
#define lazy(rt) tr[rt].lazy
#define Max(rt) tr[rt].Max
}tr[maxn << 2];
fuc(void, pushup)(int rt){ Max(rt) = maxx(Max(lsp), Max(rsp)); }
fuc(void, pushdown)(int rt){
if (lazy(rt)){
LL lz = lazy(rt);
lazy(lsp) += lz;
lazy(rsp) += lz;
Max(lsp) += lz;
Max(rsp) += lz;
lazy(rt) = 0;
}
}
fuc(void, updata)(int rt, int l, int r, int pos, LL val){
if (l == r){
Max(rt) = maxx(Max(rt), val);
return;
}
pushdown(rt);
int mid = (l + r) >> 1;
if (pos <= mid)updata(lsp, l, mid, pos, val);
if (pos > mid)updata(rsp, mid + 1, r, pos, val);
pushup(rt);
}
fuc(void, modify)(int rt, int l, int r, int L, int R, int val){
if (L <= l && r <= R){
Max(rt) += val;
lazy(rt) += val;
return;
}
pushdown(rt);
int mid = (l + r) >> 1;
if (L <= mid) modify(lsp, l, mid, L, R, val);
if (R > mid) modify(rsp, mid + 1, r, L, R, val);
pushup(rt);
}
fuc(LL, query)(int rt, int l, int r, int L, int R){
if (L <= l && r <= R){
return Max(rt);
}
pushdown(rt);
int mid = (l + r) >> 1;
LL res = 0;
if (L <= mid) res = maxx(res, query(lsp, l, mid, L, R));
if (R > mid) res = maxx(res, query(rsp, mid + 1, r, L, R));
pushup(rt);
return res;
}
signed main(){
n = read();
fr(i, 1, n){
lsh[++cnt] = wmx[i].a = read();
lsh[++cnt] = wmx[i].b = read();
wmx[i].w = read();
}
sort(wmx + 1, wmx + n + 1, cmp);
sort(lsh + 1, lsh + cnt + 1);
cnt = unique(lsh + 1, lsh + cnt + 1) - lsh - 1;
fr(i, 1, n){
wmx[i].a = lower_bound(lsh + 1, lsh + cnt + 1, wmx[i].a) - lsh;
wmx[i].b = lower_bound(lsh + 1, lsh + cnt + 1, wmx[i].b) - lsh;
}
fr(i, 1, n){
if (wmx[i].b > wmx[i].a)modify(1, 1, cnt, wmx[i].a + 1, wmx[i].b, wmx[i].w);
updata(1, 1, cnt, wmx[i].a, query(1, 1, cnt, 1, minn(wmx[i].a, wmx[i].b)) + wmx[i].w);
}
write(Max(1));
return 0;
}
/*
5
4 4 1
2 3 3
1 5 1
4 2 2
5 2 3
*/
最小距离
最水的一道题,赛时其实已经切掉了,但因为没开\(long long\)和这个题目不换行的答案输出又双叒叕爆\(0\)了
-
首先这个\(ex\)的数据范围阻止了我用\(Floyed\)的心
然后就想到了一个用\(Dij\)的神奇思路 -
首先把所有的特殊点塞进priority_queue里然后跑\(Dij\),松弛的时候记录一下是哪个特殊点更新的当前点
那么此时的\(dis\)数组实际上是存了到当前点距离最近的特殊点的距离 -
那么之后我们就可以枚举每一条边,如果他的两个端点来源相同,不用管,对答案没有贡献,如果不相同,那就将两个点的\(dis\)以及这条边的边权加起来取个\(min\)来更新答案
-
听起来就很对有木有,
虽然很暴力
点我!
#include <bits/stdc++.h>
#define LL long long
#define Re register int
#define LD long double
#define mes(x, y) memset(x, y, sizeof(x))
#define cpt(x, y) memcpy(x, y, sizeof(x))
#define fuc(x, y) inline x y
#define fr(x, y, z)for(Re x = y; x <= z; x ++)
#define fp(x, y, z)for(Re x = y; x >= z; x --)
#define frein(x) freopen(#x ".in", "r", stdin)
#define freout(x) freopen(#x ".out", "w", stdout)
#define ki putchar('\n')
#define fk putchar(' ')
#define WMX aiaiaiai~~
#define pr pair<long long, long long>
#define mk(x, y) make_pair(x, y)
using namespace std;
namespace kiritokazuto{
auto read = [](){
LL x = 0;
int f = 1;
char c;
while (!isdigit(c = getchar())){ if (c == '-')f = -1; }
do{ x = (x << 1) + (x << 3) + (c ^ 48); } while (isdigit(c = getchar()));
return x * f;
};
template <typename T> fuc(void, write)(T x){
if (x < 0)putchar('-'), x = -x;
if (x > 9)write(x / 10); putchar(x % 10 | '0');
}
}
using namespace kiritokazuto;
const int maxn = 4e5 + 10, Mod = 1e9 + 7;
const int Inf = 2147483647;
/*
她在夜里穿过我梦中的湖,在它的岸边,我看见过诸神漫步,而从湖心深处,我的魔法城堡升起。
*/
/*
上来n和m就这么大
连个floyed的分都不给?
那我跑n遍Dij?
e.........忽然发现一个问题
我拿Dij记录一下谁更新的它的最短路不就行了。。。
*/
struct Node{
int to, next;
LL dis;
}wmx[maxn];
struct Path{
int from, to;
LL dis;
}path[maxn];
priority_queue<pr> q;
LL dis[maxn];
//dis[to]表示它到更新它的特殊点(最近的那个)的距离
//一度仍然想用Spfa。。。
bool vis[maxn];
int len = 0, head[maxn];
fuc(void, Qian)(int from, int to, LL dis){
wmx[++len].to = to;
wmx[len].dis = dis;
wmx[len].next = head[from];
head[from] = len;
}
//好久没写过这样全家大团圆的dij了
int n, m, p;
int is[maxn];
LL ans[maxn];
LL from[maxn];
fuc(void, Dij)(){
while (!q.empty()){
pr top = q.top();
q.pop();
if (vis[top.second])continue;
vis[top.second] = 1;
for (Re i = head[top.second]; i; i = wmx[i].next){
int to = wmx[i].to;
if (dis[to] > dis[top.second] + wmx[i].dis){
dis[to] = dis[top.second] + wmx[i].dis;
from[to] = from[top.second];
q.push(mk(-dis[to], to));
}
}
}
}
fuc(LL, minn)(LL x, LL y){ return (x > y) ? y : x; }
/*
此生已过半
昨日依附的青山
望断这世间
的尘缘
*/
signed main(){
// frein(in);
// freout(out);
n = read();
m = read();
p = read();
mes(dis, 0x3f);
mes(ans, 0x3f);
//好险,幸好又大样例,memset mes小了...
//又怕大又怕小的,真是
fr(i, 1, p){
is[i] = read();
dis[is[i]] = 0;
from[is[i]] = is[i];
q.push(mk(0, is[i]));
}
fr(i, 1, m){
int x = path[i].from = read(), y = path[i].to = read(), z = path[i].dis = read();
Qian(x, y, z);
Qian(y, x, z);
}
Dij();
// fr(i, 1, n){
// printf("dis[%d] = %d from[%d] = %d\n", i, dis[i], i, from[i]);
// }
fr(i, 1, m){
int pre = path[i].from, to = path[i].to;
if (from[pre] == from[to])continue;
// printf("from[%d] = %d from[%d] = %d ans[%d] = %d\n", pre, from[pre], to, from[to], from[pre], ans[from[pre]]);
ans[from[pre]] = minn(ans[from[pre]], dis[pre] + dis[to] + path[i].dis);
ans[from[to]] = minn(ans[from[to]], dis[pre] + dis[to] + path[i].dis);
}
fr(i, 1, p){
write(ans[is[i]]);
fk;
}
return 0;
}
真相
-
首先如果没有\(\$\)这个东西的话,我们其实可以直接判断,如果$ \ - $ 号有奇数个的话,直接就是\(inconsistent\),具体为啥自己手模一下就可以(其实就是假设第一个是真或者假,一路推过去最后看有没有矛盾就行)
-
其次考虑有\(\$\)这个东西,它其实将我们的加减串给分隔开了,所以在一个区间内,我们是仍然可以来推的,同时如果一个说第一种话的人的话的真假被确定了,那么直到上一个说这种话的人这段区间里人的话的真假就相当于是被确定了,而一个人的话只有两种情况,所以其实可以处理一下如果这个人说真或者假话时这个区间里说真或者假话的人数,最后把所有区间合并一下,扫一下看看有没有人数使和\(\$\)合法的,判断即可
here
#include <bits/stdc++.h>
#define LL long long
#define Re register int
#define LD long double
#define mes(x, y) memset(x, y, sizeof(x))
#define cpt(x, y) memcpy(x, y, sizeof(x))
#define fuc(x, y) inline x y
#define fr(x, y, z)for(Re x = y; x <= z; x ++)
#define fp(x, y, z)for(Re x = y; x >= z; x --)
#define frein(x) freopen(#x ".in", "r", stdin)
#define freout(x) freopen(#x ".out", "w", stdout)
#define ki putchar('\n')
#define fk putchar(' ')
#define WMX aiaiaiai~~
#define pr pair<long long, long long>
#define mk(x, y) make_pair(x, y)
using namespace std;
namespace kiritokazuto{
auto read = [](){
LL x = 0;
int f = 1;
char c;
while (!isdigit(c = getchar())){ if (c == '-')f = -1; }
do{ x = (x << 1) + (x << 3) + (c ^ 48); } while (isdigit(c = getchar()));
return x * f;
};
template <typename T> fuc(void, write)(T x){
if (x < 0)putchar('-'), x = -x;
if (x > 9)write(x / 10); putchar(x % 10 | '0');
}
}
using namespace kiritokazuto;
const int maxn = 1e5 + 10, Mod = 1e9 + 7;
const int Inf = 2147483647;
#define int long long
int t;
int cut;
int fg[maxn], tr[maxn], fs[maxn];
int up[maxn], down[maxn];
struct Node{
int opt;
int x;
#define opt(x) wmx[x].opt
#define x(xx) wmx[xx].x
}wmx[maxn];
signed main(){
t = read();
int n;
while (t--){
n = read();
cut = 0;
fr(i, 1, n){
char c;
// cin >> c;
scanf(" %c", &c);
// printf("%c \n", c);
if (c == '+')opt(i) = 1;
else if (c == '-')opt(i) = 2;
else{
if (!cut)cut = i;
opt(i) = 3;
x(i) = read();
}
}
// printf("here is victor");
if (!cut){
int cnt = 0;
fr(i, 1, n){
if (opt(i) == 2)cnt++;
}
if (cnt & 1){
printf("inconsistent\n");
continue;
}
else{
printf("consistent\n");
continue;
}
}
else{
fr(i, n + 1, n * 2)wmx[i] = wmx[i - n];
int tot = 0;
fr(i, 0, n) fs[i] = tr[i] = fg[i] = 0;
up[cut + 1] = 1;
down[cut + 1] = 0;
fr(i, cut + 1, cut + n){
if (opt(i) == 3){
up[i + 1] = 1;
down[i + 1] = 0;
tot += down[i];
if (x(i) <= n){
tr[x(i)] += up[i];
fs[x(i)] += down[i];
fg[x(i)] = 1;
}
}
else if (opt(i) == 2){
up[i + 1] = down[i] + 1;
down[i + 1] = up[i];
}
else{
up[i + 1] = up[i] + 1;
down[i + 1] = down[i];
}
}
if (!fg[tot]){
printf("consistent\n");
continue;
}
bool fgg = 0;
fr(i, 1, n){
if (fg[i]){
if (tot - fs[i] + tr[i] == i){
printf("consistent\n");
fgg = 1;
break;
}
}
}
if (fgg)continue;
printf("inconsistent\n");
}
}
return 0;
}
标签:fr,wmx,数列,int,LL,数对,lsh,集训,define 来源: https://www.cnblogs.com/kiritokazuto/p/16597447.html