D1T1 玩具谜题

xjb模拟即可

#include<bits/stdc++.h>
#define N (100000+5)
using namespace std;
inline int read() {
int cnt = 0, f = 1; char c;
c = getchar();
while (!isdigit(c)) {
if (c == '-') f = -f;
c = getchar();
}
while (isdigit(c)) {
cnt = (cnt << 3) + (cnt << 1) + c - '0';
c = getchar();
}
return cnt * f;
}
int n, m;
struct node{
int opr;
char name[20];
} a[N];
int s, t, p;
int main() {
n = read(); m = read();
for (register int i = 1; i <= n; i++) {
a[i].opr = read();
scanf("%s\n", a[i].name + 1);
}
p = 1;
for (register int i = 1; i <= m; i++) {
s = read(); t = read();
if (s == a[p].opr) {
p -= t;
p += n;
p %= n;
if (p == 0) p = n;
} else {
p += t;
p %= n;
if (p == 0) p = n;
}
}
for (register int i = 1; i <= strlen(a[p].name + 1); i++) putchar(a[p].name[i]);
return 0;
}

D1T2 天天爱跑步

神仙题各色乱搞大杂烩集中营 我也不知道为什么它会出现在\(D1T2\) 单独写

D1T3 换教室

期望\(dp\),设\(dp[i][j][0/1]\)表示考虑到第\(i\)门课,已经换了\(j\)门,这次换/不换的答案

状态转移时,按这次申请换/不换分别考虑,若这次不换则这次的选择一定是百分百不换,那么分别算一下上一次换没换成功对答案贡献即可

若这次换那么分开考虑上次换成功与否(这决定了我们用哪一个状态转移),若上次不换则有两种情况,这次成功/不成功;若上次换则有四种情况,即这次成功与否和上次成功与否乘法原理组合一下,对答案的贡献就是它们分别要走的路程分别乘上它们时间发生的概率

方程比较窒息,建议手推一下或直接看代码

\[dp[i][j][0] = min \left\{ \begin{aligned} &dp[i - 1][j][0] + Map[c[i - 1]][c[i]] \\ &dp[i - 1][j][1] + Map[c[i - 1]][c[i]] * (1 - k[i - 1]) + Map[d[i - 1]][c[i]] * k \end{aligned} \right.
\]

\[dp[i][j][1] = \left\{ \begin{aligned} &dp[i - 1][j - 1][0] + Map[c[i - 1]][d[i ]] * k[i] + Map[c[i - 1]][c[i]] * (1 - k[i]) \\ &dp[i - 1][j - 1][1] + Map[c[i - 1]][d[i]] * (1 - k[i - 1]) * k[i] + Map[d[i - 1]][d[i]] * k[i - 1] * k[i] + Map[c[i - 1]][c[i]] * (1 - k[i]) * (1 - k[i - 1]) + Map[d[i - 1]][c[i]] * k[i - 1] * (1 - k[i]) \end{aligned} \right.
\]

因为数据范围很小,教室之间距离用\(Floyd\)求出即可

#include<bits/stdc++.h>
#define N (2000 + 10)
using namespace std;
inline int read() {
int cnt = 0, f = 1; char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + (c ^ 48); c = getchar();}
return cnt * f;
}
int n, m, v, e, a[N], b[N], Map[305][305], dis[305][305]; //2n-course, max_request = m, v = num_of_vertex, e = num_of_edge
double k[N], f[N][N][2], ans;
int x, y, w;
void get() {
n = read(), m = read(), v = read(), e = read();
for (register int i = 1; i <= v; ++i)
for (register int j = 1; j <= v; ++j)
dis[i][j] = Map[i][j] = 1e9;
for (register int i = 1; i <= n; ++i) a[i] = read();
for (register int i = 1; i <= n; ++i) b[i] = read();
for (register int i = 1; i <= n; ++i) scanf("%lf", &k[i]);
for (register int i = 1; i <= e; ++i) {
x = read(), y = read(), w = read();
dis[x][y] = dis[y][x] = Map[x][y] = Map[y][x] = min(Map[x][y], w);
}
}
int main() {
get();
for (register int i = 1; i <= v; ++i) dis[i][i] = Map[i][i] = 0;
for (register int p = 1; p <= v; ++p)
for (register int i = 1; i <= v; ++i)
for (register int j = 1; j <= v; ++j) dis[i][j] = min(dis[i][j], dis[i][p] + dis[p][j]); for (register int i = 0; i <= n; ++i)
for (register int j = 0; j <= m; ++j) f[i][j][0] = f[i][j][1] = 1e9;
f[1][0][0] = f[1][1][1] = 0;
for (register int i = 2; i <= n; ++i) f[i][0][0] = f[i - 1][0][0] + dis[a[i - 1]][a[i]];
for (register int i = 2; i <= n; ++i)
for (register int j = 1; j <= m; ++j) {
f[i][j][0] = min(f[i][j][0], min(f[i - 1][j][0] + dis[a[i - 1]][a[i]], f[i - 1][j][1] + (1 - k[i - 1]) * dis[a[i - 1]][a[i]] + k[i - 1] * dis[b[i - 1]][a[i]]));
f[i][j][1] = min(f[i][j][1],
min(f[i - 1][j - 1][0] + dis[a[i - 1]][a[i]] * (1 - k[i]) + dis[a[i - 1]][b[i]] * k[i],
f[i - 1][j - 1][1] + dis[b[i - 1]][a[i]] * (1 - k[i]) * k[i - 1] + dis[b[i - 1]][b[i]] * k[i] * k[i - 1] + dis[a[i - 1]][a[i]] * (1 - k[i - 1]) * (1 - k[i]) + dis[a[i - 1]][b[i]] * (1 - k[i - 1]) * k[i])) ;
}
ans = 1e9;
for (register int i = 0; i <= m; ++i) {
if (f[n][i][0] < ans) ans = f[n][i][0];
if (f[n][i][1] < ans) ans = f[n][i][1];
}
printf("%.2lf", ans);
return 0;
}

D2T1 组合数问题

组合恒等式求组合数+二维前缀和统计答案

#include<bits/stdc++.h>
#define int long long
#define N (2000 + 10)
using namespace std;
inline int read() {
int cnt = 0, f = 1; char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + (c ^ 48); c = getchar();}
return cnt * f;
}
int n, m, k, T;
int c[N][N], ans[N][N];
void pre_work() {
c[1][1] = c[0][0] = c[1][0] = 1;
for (register int i = 2; i <= 2000; ++i) {
c[i][0] = 1;
for (register int j = 1; j <= i; ++j) {
c[i][j] = (c[i - 1][j] % k + c[i - 1][j - 1] % k) % k;
ans[i][j] = ans[i - 1][j] + ans[i][j - 1] - ans[i - 1][j - 1] + (!c[i][j]) ;
}
ans[i][i + 1] = ans[i][i];
}
}
signed main() {
T = read(), k = read();
pre_work();
while (T--){
n = read(), m = read();
printf("%lld\n", m < n ? ans[n][m] : ans[n][n]);
}
return 0;
}

D2T2 蚯蚓

乍一看以为是个优先队列的\(sb\)题,冷静看了看数据范围发现优先队列过不去

发现题目隐含着很妙的单调性,因为每次取的是最长的蚯蚓切开,切的方式(切割的系数)是一样的,那么一定有先切开的蚯蚓比后切开的蚯蚓长这个结论

所以开三个单调队列,一个维护原来的蚯蚓,一个维护\(\lfloor px \rfloor\),一个维护\(x - \lfloor px \rfloor\),每次取出三个队列的队头比较一下再切割即可

再维护一下时间增长,查询时直接把增量加上去,每次切割出的两条新蚯蚓不会得到这一秒的增长量,那么在它们的值上减一下即可

#include<bits/stdc++.h>
#define int long long
#define N (8000000 + 50)
using namespace std;
inline int read() {
int cnt = 0, f = 1; char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + (c ^ 48); c = getchar();}
return cnt * f;
}
int n, m, q, u, v, t, ans, x, siz, a[N];
double p;
int q1[N], q2[N], q3[N];
int h1 = 1, h2 = 1, h3 = 1, t1, t2, t3;
priority_queue<int> Q;
inline int Max(int a, int b, int c) {return max(max(a, b), c);}
inline int get_Max() {
if (Max(q1[h1], q2[h2], q3[h3]) == q1[h1]) {
if (h1 <= t1) return q1[h1];
else if (q2[h2] > q3[h3] && h2 <= t2) return q2[h2];
else return q3[h3];
}
if (Max(q1[h1], q2[h2], q3[h3]) == q2[h2]) {
if (h2 <= t2) return q2[h2];
else if (q1[h1] > q3[h3] && h1 <= t1) return q1[h1];
else return q3[h3];
}
if (Max(q1[h1], q2[h2], q3[h3]) == q3[h3]) {
if (h3 <= t3) return q3[h3];
else if (q2[h2] > q1[h1] && h2 <= t2) return q2[h2];
else return q1[h1];
}
}
inline void POP() {
if (get_Max() == q1[h1]) {
if (h1 <= t1) ++h1;
else if (q2[h2] > q3[h3] && h2 <= t2) ++h2;
else ++h3;
return;
}
if (get_Max() == q2[h2]) {
if (h2 <= t2) ++h2;
else if (q1[h1] > q3[h3] && h1 <= t1) ++h1;
else ++h3;
return;
}
if (get_Max() == q3[h3]) {
if (h3 <= t3) ++h3;
else if (q2[h2] > q1[h1] && h2 <= t2) ++h2;
else ++h1;
return;
}
}
signed main() {
// freopen("1.in", "r", stdin);
n = read(), m = read();
if (m > 1000000) {
q = read(), u = read(), v = read(), t = read();
p = (double)u / v;
for (register int i = 1; i <= n; ++i) a[i] = read();
sort (a + 1, a + n + 1);
for (register int i = n; i >= 1; --i) q1[++t1] = a[i];
for (register int i = 1; i <= m; ++i) {
if (i % t == 0) {
ans = get_Max();
printf("%lld ", ans + (i - 1) * q);
}
x = get_Max() + (i - 1) * q;
POP();
q2[++t2] = x - (int)(p * (double) x) - i * q, q3[++t3] = (int)(p * (double) x) - i * q;
}
printf("\n");
for (register int i = 1; i <= n + m; ++i) {
if (i % t == 0) printf("%lld ", get_Max() + m * q);
POP();
}
} else {
q = read(), u = read(), v = read(), t = read();
p = (double)u / (double) v;
for (register int i = 1; i <= n; ++i) x = read(), Q.push(x);
for (register int i = 1; i <= m; ++i) {
if (i % t == 0) {
ans = Q.top();
printf("%d ", ans + (i - 1) * q);
}
x = Q.top() + (i - 1) * q; Q.pop();
Q.push((int)(p * (double)x) - i * q), Q.push(x - (int)(p * (double)x) - i * q);
}
printf("\n");
siz = Q.size();
for (register int i = 1; i <= siz; ++i) {
if (i % t == 0) printf("%d ", Q.top() + m * q);
Q.pop();
}
}
return 0;
}

D2T3 愤怒的小鸟

神仙状压,很多题解的做法复杂度是假的

记录一下分析过程

因为这一年别的题没有dp所以我们考虑dp

看看数据范围,\(n \leq 18\),考虑怎么状压一下

参照洛谷第一篇题解的思路,想想怎么样设计状态

设\(dp[S]\)表示已经死了的猪的集合为\(S\),要达到这个状态\(S\)所需要发射的鸟有多少只

首先两两预处理一下经过这两点的抛物线解析式(反正只可能是形如\(ax^2 + bx\)的形式,怎么瞎搞都可),注意跳过\(x\)相等的情况,然后把这两点塞进\(line[a][b]\)这个集合内,\(line[a][b]\)表示抛物线\(ax^2 + bx\)经过的所有点的集合状态

考虑一次打一条抛物线的情况,一次打一只猪的情况以及初始状态,得到最朴素的状态转移方程

\[dp[0][0] = 0\\
dp[S|line[i][j]] = min(dp[S] + 1)\\
dp[S|(1<<(i - 1))] = min(dp[S] + 1)\\
\]

冷静分析一波发现这个的复杂度是\(O(Tn^2 2^n)\)的,然鹅并跑不过

考虑优化

对于每个集合\(S\),我们发现第一只打不着的猪(即满足\(S\&(1<<(x - 1))\)的最小正整数\(x\)),即使我们现在转移的时候不打它,之后也得回过头来把它打掉,于是预处理一下就能做到\(O(Tn2^n)\),不过这里没有预处理,但也差不多

#include<bits/stdc++.h>
#define INF (1000000000 + 7)
#define N (20 + 5)
#define eps 1e-10
using namespace std;
inline int read() {
int cnt = 0, f = 1; char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + (c ^ 48); c = getchar();}
return cnt * f;
}
int t, n, m, f[2000000], num[N][N];
double x[N], y[N];
bool same(double x, double y) {return fabs(x - y) < eps;}
int main() {
t = read();
while (t--) {
n = read(), m = read();
for (register int i = 1; i <= n; ++i) scanf("%lf%lf", &x[i], &y[i]);
for (register int i = 1; i <= n; ++i)
for (register int j = 1; j <= n; ++j) num[i][j] = 0;
for (register int i = 1; i < n; ++i)
for (register int j = i + 1; j <= n; ++j) {
if (same(x[i], x[j])) continue;
double a = (y[j] / x[j] - y[i] / x[i]) / (x[j] - x[i]);
if (a >= 0) continue;
double b = y[i] / x[i] - a * x[i];
for (register int k = 1; k <= n; ++k)
if (same(a * x[k] + b, y[k] / x[k])) num[i][j] |= (1 << (k - 1));
}
for (register int i = 0; i <= (1 << n) - 1; ++i) f[i] = INF; f[0] = 0;
for (register int i = 0; i <= (1 << n) - 1; ++i)
for (register int j = 1; j <= n; ++j) if (!(i & (1 << j - 1))) {
for (register int k = j; k <= n; ++k) {
if (j == k) f[i|(1 << (j - 1))] = min(f[i | (1 << (j - 1))], f[i] + 1);
if (same(x[j], x[k])) continue;
f[i | num[j][k]] = min(f[i | num[j][k]], f[i] + 1);
}
break;
}
printf("%d\n", f[(1 << n) - 1]);
}
return 0;
}

NOIP2016 解题报告的更多相关文章

  1. NOIP2016解题报告

    天天听这几道题,但其实题面都没看过.今天做一下. 每道题看懂题后基本一分钟左右就切了.D2T3想的是\(O(n\log n)\)的堆做法,至少90分吧. D1T1模拟即可. D1T2每条路径拆成到根的 ...

  2. NOIP2016提高组解题报告

    NOIP2016提高组解题报告 更正:NOIP day1 T2天天爱跑步 解题思路见代码. NOIP2016代码整合

  3. 二模13day1解题报告

    二模13day1解题报告 T1.发射站(station) N个发射站,每个发射站有高度hi,发射信号强度vi,每个发射站的信号只会被左和右第一个比他高的收到.现在求收到信号最强的发射站. 我用了时间复 ...

  4. CH Round #56 - 国庆节欢乐赛解题报告

    最近CH上的比赛很多,在此会全部写出解题报告,与大家交流一下解题方法与技巧. T1 魔幻森林 描述 Cortana来到了一片魔幻森林,这片森林可以被视作一个N*M的矩阵,矩阵中的每个位置上都长着一棵树 ...

  5. BZOJ 1051 最受欢迎的牛 解题报告

    题目直接摆在这里! 1051: [HAOI2006]受欢迎的牛 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4438  Solved: 2353[S ...

  6. 习题:codevs 2822 爱在心中 解题报告

    这次的解题报告是有关tarjan算法的一道思维量比较大的题目(真的是原创文章,希望管理员不要再把文章移出首页). 这道题蒟蒻以前做过,但是今天由于要复习tarjan算法,于是就看到codevs分类强联 ...

  7. 习题:codevs 1035 火车停留解题报告

    本蒟蒻又来写解题报告了.这次的题目是codevs 1035 火车停留. 题目大意就是给m个火车的到达时间.停留时间和车载货物的价值,车站有n个车道,而火车停留一次车站就会从车载货物价值中获得1%的利润 ...

  8. 习题: codevs 2492 上帝造题的七分钟2 解题报告

    这道题是受到大犇MagHSK的启发我才得以想出来的,蒟蒻觉得自己的代码跟MagHSK大犇的代码完全比不上,所以这里蒟蒻就套用了MagHSK大犇的代码(大家可以关注下我的博客,友情链接就是大犇MagHS ...

  9. 习题:codevs 1519 过路费 解题报告

    今天拿了这道题目练练手,感觉自己代码能力又增强了不少: 我的思路跟别人可能不一样. 首先我们很容易就能看出,我们需要的边就是最小生成树算法kruskal算法求出来的边,其余的边都可以删掉,于是就有了这 ...

随机推荐

  1. bean创建

    看<spring源码解析>的笔记 1.通过@Bean创建bean,类上需要添加@Configuration @Configuration public class MainConfig { ...

  2. Spring容器对Bean组件的管理

    Bean对象创建 默认是随着容器创建 可以使用 lazy-init=true:在调用 getBean 延迟创建 也可以用 <beans default-lazy-init="true& ...

  3. thinkphp 模块部署

    3.2对模块的访问是自动判断的,所以通常情况下无需配置模块列表即可访问,在部署模块的时候,默认情况下都是基于类似于子目录的URL方式来访问模块的,例如: http://serverName/Home/ ...

  4. 「题解」:07.16NOIP模拟T1:礼物

    问题 A: 礼物 时间限制: 1 Sec  内存限制: 256 MB 题面 题目描述 夏川的生日就要到了.作为夏川形式上的男朋友,季堂打算给夏川买一些生 日礼物. 商店里一共有种礼物.夏川每得到一种礼 ...

  5. 移动Windows开始按钮到任务栏中的任何位置

    uses CommCtrl; procedure TForm1.Button1Click(Sender: TObject); var vHandle: THandle; vCount: Integer ...

  6. 双目立体匹配经典算法之Semi-Global Matching(SGM)概述:视差计算、视差优化

    文章目录 视差计算 视差优化 剔除错误匹配 提高视差精度 抑制噪声 视差计算   在SGM算法中,视差计算采用赢家通吃(WTA)算法,每个像素选择最小聚合代价值所对应的视差值作为最终视差,视差计算的结 ...

  7. NX二次开发-UFUN获取当前导出CGM选项设置UF_CGM_ask_session_export_options

    文章转载自唐康林NX二次开发论坛,原文出处: http://www.nxopen.cn/thread-126-1-1.html 刚才有同学问到这个问题,如果是用NXOpen来做,直接录制一下就可以了: ...

  8. 2018-2019-2-20175323 java实验二《Java面向对象程序设计》

    单元测试 1.在IDEA中新建项目并输入单元测试的代码 2.在IDEA中下载Junit,我发现Junit已经存在了 3.新建test文件 遇到的问题 发现Junit红字解析不了 解决办法:查找到jun ...

  9. Git 本地仓库管理

    目录 目录 基本概念 配置 配置个人帐号信息 安装 本地版本库 创建 Git 仓库 Git 仓库版本回退 修改管理 基本概念 工作区(Working Directory): 就是你在电脑里能看到的目录 ...

  10. NetBeans简介和简单使用

    1.什么是NetBeans? NetBeans IDE:可以使开发人员利用Java平台能够快速创建Web.企业.桌面以及移动的应用程序: 支持语言:PHP.Ruby.JavaScript.Groovy ...