【转】常用memset极值
本文章部分节选自【自用】 memset对于int、long long、float、doub …
May all the beauty be blessed.
作词:Aimer
作曲:飛内将大
歌:Aimer
歌词来源:六等星の夜 – Aimer – 单曲 – 网易云音乐
翻译来源:六等星の夜 – Aimer – 单曲 – 网易云音乐
翻译作者:虎纹鲨鱼子 – 用户 – 网易云音乐
信息来源:六等星の夜/悲しみはオーロラに/TWINKLE TWINKLE LITTLE STAR | Bangumi 番组计划
罗马音来源:自制 航空母艦飛龍 – 用户 – 网易云音乐
协力:Google 翻译
傷ついたときは
Kizutsuita toki wa
〖每当我受伤〗
そっと包みこんでくれたらうれしい
Sotto tsutsumi konde kuretara ureshī
〖你能轻轻拥抱我的话该多开心〗
転んで立てないときは
Koronde tatenai toki wa
〖每当我跌倒站不起来〗
少しの勇気をください
Sukoshi no yūki o kudasai
〖请给予我一丝勇气〗
想いはずっと届かないまま
Omoi wa zutto todokanai mama
〖内心的思念一直无法传达〗
今日も冷たい街でひとり
Kyō mo tsumetai machi de hitori
〖今天也独自走在寒冷的街上〗
ココが何処かも思い出せない
Koko ga doko kamo omoidasenai
〖就连这里是哪里也回想不起来〗
終わらない夜に願いはひとつ
Owaranai yoru ni negai wa hitotsu
〖永无终止的黑夜 愿望只有一个〗
“星のない空に輝く光を”
Hoshi no nai sora ni kagayaku hikari o
〖”给无星光的夜空献上璀璨的光芒”〗
戻れない場所に捨てたものでさえ
Modorenai basho ni suteta monode sae
〖在无法返回的地方 所舍弃的事物〗
生まれ変わって明日をきっと照らす
Umarekawatte ashita o kitto terasu
〖也必将重获新生 照亮明天〗
星屑のなかであなたに出会えた
Hoshikuzu no naka de anata ni deaeta
〖在满天星光下与你相遇〗
いつかの気持ちのまま会えたらよかった
Itsuka no kimochi no mama aetara yokatta
〖能怀着曾几何时的心情遇上你该多好〗
戻らない過去に泣いたことでさえ
Modoranai kako ni naita kotode sae
〖为一去不返的过去所流的泪水〗
生まれ変わって明日をきっと照らしてくれる
Umarekawatte ashita o kitto terashite kureru
〖也必将重获新生 为我照亮明天〗
眠れないときは
Nemurenai toki wa
〖每当我辗转难眠〗
そっと手をつないでくれたらうれしい
Sotto te o tsunaide kuretara ureshī
〖你能悄悄牵住我的手的话该多开心〗
夜明けは来るよと
Yoake wa kuru yo to
〖请轻声告诉我〗
囁いていて 嘘でもいいから
Sasayaite ite usodemoīkara
〖黎明必将来临 谎言也无所谓〗
願いはずっと叶わないまま
Negai wa zutto kanawanai mama
〖愿望一直都未曾实现〗
今夜 星座を連れ去って
Kon’ya seiza o tsuresatte
〖今夜 带着星座〗
消えてしまったもう、戻れない…
Kiete shimatta mō, modorenai
〖消逝于夜空中 再也无法归来〗
終わらない夜に願いはひとつ
Owaranai yoru ni negai wa hitotsu
〖永无终止的黑夜 愿望只有一个〗
“星のない空に輝く光を”
Hoshi no nai sora ni kagayaku hikari o
〖”给无星光的夜空献上璀璨的光芒”〗
今は遠すぎて儚い星でも
Ima wa tō sugite hakanai hoshi demo
〖如今纵使星粒遥远而渺茫〗
生まれ変わって夜空をきっと照らす
Umarekawatte yozora o kitto terasu
〖也必将重获新生 照亮夜空〗
星屑のなかで出会えた奇跡が
Hoshikuzu no naka de deaeta kiseki ga
〖在满天星屑下邂逅上你的奇迹〗
人ゴミのなかにまた見えなくなる
Hito gomi no naka ni mata mienaku naru
〖又在茫茫人海当中稍纵即逝〗
戻らない過去に泣いた夜たちに
Modoranai kako ni naita yoru-tachi ni
〖为一去不返的过去而哭泣的夜晚〗
告げるサヨナラ明日はきっと輝けるように
Tsugeru sayonara ashita wa kitto kagayakeru yō ni
〖道一声再见 明天一定会栩栩生辉〗
こんなちいさな星座なのに
Kon’na chīsana seizananoni
〖明明是如此微小的星座〗
ココにいたこと 気付いてくれて
Kokonīta koto kidzuite kurete
〖你却能够注意到我存在于此〗
ありがとう
Arigatō
〖感激不尽〗
終わらない夜に願いはひとつ
Owaranai yoru ni negai wa hitotsu
〖永无终止的黑夜 愿望只有一个〗
“星のない空に輝く光を”
Hoshi no nai sora ni kagayaku hikari o
〖”给无星光的夜空献上璀璨的光芒”〗
戻れない場所に捨てたものでさえ
Modorenai basho ni suteta monode sae
〖在无法返回的地方 所舍弃的事物〗
生まれ変わって明日をきっと照らす
Umarekawatte ashita o kitto terasu
〖也必将重获新生 照亮明天〗
星屑のなかであなたに出会えた
Hoshikuzu no naka de anata ni deaeta
〖在满天星光下与你相遇〗
いつかの気持ちのまま会えたらよかった
Itsuka no kimochi no mama aetara yokatta
〖能怀着曾几何时的心情遇上你该多好〗
戻らない過去に泣いたことでさえ
Modoranai kako ni naita kotode sae
〖为一去不返的过去所流的泪水〗
生まれ変わって明日をきっと照らしてくれる
Umarekawatte ashita o kitto terashite kureru
〖也必将重获新生 为我照亮明天〗
KSkun
赛题 #A: 负负得正 | 数学,数论,组合数学
赛题 #B: 疯狂的FGOer | 期望DP,二分答案
赛题 #C: Kirara Fantasia的一天 | 图论,Tarjan,缩点,DAGDP
求构建出元素全为1或-1的一个n \times m的矩阵并使得每行每列的乘积都为1或都为-1的方案数。
仅输出0可得25分。
枚举,瞎搞。
优化:我们知道,枚举出n-1行m-1列后剩下的一行一列的值是可以唯一确定的,所以只需要枚举n-1行m-1列的一个矩阵。
总复杂度O(2^{(n-1)(m-1)})。
我们只需要把n-1行m-1列的矩阵填完,剩下一行一列的值可以确定,而且对于任意填法都可以确定。考虑右下角(即第n行第m列)的元素。假设n-1行m-1列矩阵整个的乘积为p,对于最后一列而言,这个位置应当填k^{m-1}p,而对于最后一行而言,这个位置应当填k^{n-1}p。显然当n和m的奇偶性不同且k为-1时,不存在任何一种填法满足要求。其余情况只要填满了n-1行m-1列矩阵都可以成立。因此总方案数是2^{(n-1)(m-1)}。快速幂处理即可。
这个部分分是因为如果你用int存后面的部分分会爆炸,特意设了一档。
总复杂度O(log_2((n-1)(m-1)))。
写long long。
欧拉降幂公式:
a^{k} \equiv a^{k \ mod \ \varphi(m) + \varphi(m)} \ (mod \ m)
继而缩小指数的范围,优化时空复杂度。
// Code by KSkun, 2017/12
#include <cstdio>
const int MO = 1e9 + 7;
long long n, m, k;
inline long long fpow(long long n, long long k) {
long long res = 1;
for(; k; k >>= 1) {
if(k & 1) res = res * n % MO;
n = n * n % MO;
}
return res;
}
int main() {
scanf("%lld%lld%lld", &n, &m, &k);
if(k == -1 && (n & 1) != (m & 1)) printf("0");
else printf("%lld", fpow(2, ((n - 1) % (MO - 1)) * ((m - 1) % (MO - 1)) % (MO - 1) + (MO - 1)));
return 0;
}
CF894B – Ralph And His Magic Field
有一系列任务,每一任务都有一定概率快或慢完成,每个任务完成后可以选择继续完成接下来的任务或是从头开始完成,求一种选择是否从头开始的策略使得完成全部任务的期望值最小。
直接把A_i加起来。
总复杂度O(n)。
出题事故:50%部分分的写法被证实是错误的,因此还没有想到能够用于50%部分分的写法。
原错解:
考虑当我们重置游戏的时候会发生什么。一定是当出现较长时间时重置比较优。如果不重置,每一关的期望应该是上一关期望加上A_i*P_i+B_i*(1-P_i);而如果重置了,则是(exp_{i-1}+B_i)*prob+A_i。此处prob指尝试的次数,可以由题目提示中的方法算出。比较二者大小然后选择即可。但是对于t限制比较严格的数据,由于这里没有剔除超t的可能性,很容易WA。事实证明,这个方法只能过40%的点。由于时间关系,没有对这一层设置部分分,实在抱歉。
考虑对题目模型加以改造。我们假设从头开始进行完游戏的期望是K。这样一种考虑方案需要我们从末尾开始DP计算期望。设计DP状态为:dp[i][j]表示当前计算到第i关,一共用去了j时间,通关的期望。转移:
对于K这个数字,我们发现,它在较大的时候容易满足条件,满足条件的取值是单调的,具有二分性质。考虑二分答案计算K。每计算出一次通关期望,即用其与所设的K比较,若比K小则显然可行。
复杂度O(n^2logn)。
// Code by KSkun, 2017/12
#include <cstdio>
#include <algorithm>
const double EPS = 1e-8;
double dp[55][5005], p[55];
int a[55], b[55], n, t;
inline bool check(double x) {
for(int i = n - 1; i >= 0; i--) {
for(int j = t + 1; j < 5005; j++) {
dp[i + 1][j] = x;
}
for(int j = 0; j <= t; j++) {
dp[i][j] = std::min(x, (dp[i + 1][j + a[i]] + a[i]) * p[i] + (dp[i + 1][j + b[i]] + b[i]) * (1 - p[i]));
}
}
return dp[0][0] < x;
}
int main() {
scanf("%d%d", &n, &t);
for(int i = 0; i < n; i++) {
scanf("%d%d%lf", &a[i], &b[i], &p[i]);
}
double l = 0, r = 1e10, mid;
while(r - l > EPS) {
mid = (l + r) / 2;
if(check(mid)) r = mid; else l = mid;
}
printf("%.2lf", l);
return 0;
}
给一个有向图,边权每次经过时按照一定的规则递减(第一次-1,第二次-2,以此类推),求一条路径使边权最大。
图这么大,显然跑不动。
考虑强连通分量内部的状况,显然是可以跑多几次使得每条边边权全部为0的,因此主要策略是Tarjan缩点+拓扑序DP(用于最长路,你也可以SPFA,没写过)。
如果想把一条边的边权踩完,你需要对这样一个数列求和
\sum_{i=k}^{w} (w-(1+2+ \cdots +i)) = \sum_{i=k}^{w} (w-\frac{i(i+1)}{2})
其中k是使得数列元素为正值的最大正整数。这个数列求和就变成了
\frac{n(n+1)(n+2)}{6}
因此有了代码中cal()
函数的写法。
其他的拓扑序DP找最长路,比较显然,不加以解释。
友情提示:全程用long long
,记得写快读。
复杂度O(n+m)。
// Code by KSkun, 2017/12
#include <cstdio>
#include <cstring>
#include <cmath>
#include <stack>
#include <queue>
#include <algorithm>
typedef long long LL;
const LL inf = 1e15;
struct io {
char buf[1 << 26], *s;
io() {
fread(s = buf, 1, 1 << 26, stdin);
}
inline LL read() {
register LL res = 0;
while(*s < '0' || *s > '9') s++;
while(*s >= '0' && *s <= '9') res = res * 10 + *s++ - '0';
return res;
}
} ip;
#define read ip.read
struct Edge {
int to, nxt;
LL w;
};
struct Graph {
Edge gra[1000005];
int head[1000005], rd[1000005], tot;
LL w[1000005];
Graph() {
memset(head, -1, sizeof head);
tot = 0;
}
inline void addedge(int u, int v, LL w) {
gra[tot].to = v;
gra[tot].w = w;
gra[tot].nxt = head[u];
rd[v]++;
head[u] = tot++;
}
};
int n, m;
Graph g1, g2;
int dfn[1000005], low[1000005], step = 1, sccno[1000005], scctot = 1;
bool instack[1000005];
std::stack<int> sta;
inline void tarjan(int s) {
dfn[s] = low[s] = step++;
instack[s] = true;
sta.push(s);
for(int e = g1.head[s]; e != -1; e = g1.gra[e].nxt) {
int v = g1.gra[e].to;
if(dfn[v] == 0) {
tarjan(v);
low[s] = std::min(low[s], low[v]);
} else if(instack[v]) {
low[s] = std::min(low[s], dfn[v]);
}
}
if(dfn[s] == low[s]) {
LL totw = 0;
while(sta.top() != s) {
sccno[sta.top()] = scctot;
instack[sta.top()] = false;
sta.pop();
}
sccno[sta.top()] = scctot;
instack[sta.top()] = false;
sta.pop();
scctot++;
}
}
inline LL cal(LL w) {
LL n = sqrt(2 * w + 0.25) - 0.5;
return n * w - n * (n + 1) * (n + 2) / 6 + w;
}
inline void calg2() {
for(int u = 1; u <= n; u++) {
for(int e = g1.head[u]; e != -1; e = g1.gra[e].nxt) {
int v = g1.gra[e].to;
if(sccno[u] == sccno[v]) {
g2.w[sccno[u]] += cal(g1.gra[e].w);
} else {
g2.addedge(sccno[u], sccno[v], g1.gra[e].w);
}
}
}
}
std::queue<int> que;
LL ans = 0, dp[1000005];
inline void toposort(int s) {
for(int i = 1; i < scctot; i++) {
dp[i] = -inf;
if(g2.rd[i] == 0) que.push(i);
}
dp[s] = g2.w[s];
while(!que.empty()) {
int u = que.front();
ans = std::max(ans, dp[u]);
que.pop();
for(int e = g2.head[u]; e != -1; e = g2.gra[e].nxt) {
int v = g2.gra[e].to;
g2.rd[v]--;
if(dp[u] != -inf) dp[v] = std::max(dp[v], dp[u] + g2.gra[e].w + g2.w[v]);
if(g2.rd[v] == 0) {
que.push(v);
}
}
}
}
int ut, vt, wt;
int st;
int main() {
n = read();
m = read();
for(int i = 0; i < m; i++) {
ut = read();
vt = read();
wt = read();
g1.addedge(ut, vt, wt);
}
st = read();
for(int i = 1; i <= n; i++) {
if(dfn[i] == 0) tarjan(i);
}
calg2();
toposort(sccno[st]);
printf("%lld", ans);
return 0;
}