CF339
有1...10k的砝码,在天枰上,左右轮流放置砝码,要求之后左右轮流比另一侧重量要大,要求相邻两次砝码不能相同。
解题报告给出(i,j,k)表示balance,j表示最后一次的砝码重量,k表示第几步,然后表示从点(0,0,0)->(x,y,m)的图论问题,跟动态规划是等价的,复杂度是O(w^3*m)。
我给出了一个比上述算法更优的一个算法,做法是用dp[i][j]表示第i步balance达到j时的所有可能的砝码情况的二进制mask,复杂度是O(w^2*m),但要求w<32。
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
using namespace std; int dp[][];
char w[]; int main() {
int m;
scanf("%s%d", w, &m); memset(dp, , sizeof(dp));
dp[][] = ; for (int i = ; i <= m; i++) {
for (int j = ; j <= ; j++) {
if (dp[i - ][j] > ) {
for (int k = ; k <= ; k++) if (w[k - ] == '') {
if (dp[i - ][j] ^ ( << k)) {
if (j >= && j - k < ) {
dp[i][j - k] |= ( << k);
} else if (j < && j + k > ) {
dp[i][j + k] |= ( << k);
}
}
}
}
}
} int ans_j = -;
for (int j = ; j <= ; j++) if (dp[m][j] > )
ans_j = j; if (ans_j == -) {
printf("NO\n");
} else {
printf("YES\n");
int i = m;
vector<int> ans;
int last = ;
while (i > ) {
for (int j = ; j <= ; j++) {
if (dp[i][ans_j] & ( << j)) {
if (j == last) continue; ans.push_back(j); if (ans_j >= ) ans_j -= j;
else ans_j += j; last = j; break;
}
}
i--;
}
for (i = ans.size() - ; i >= ; i--) {
printf("%d ", ans[i]);
}
printf("\n");
}
}
很裸的一个线段树了。
#include <cstdio>
#include <iostream>
using namespace std; const int MAXN = << ; int num[MAXN]; class SegNode {
public:
int L, R;
int level, sum;
} node[MAXN * ]; class SegTree {
public:
void build(int r, int L, int R) {
node[r].L = L;
node[r].R = R; if (L == R) {
// leaf
node[r].level = ;
node[r].sum = num[L];
} else {
// non leaf
int M = (L + R) / ;
build( * r, L, M);
build( * r + , M + , R);
node[r].level = node[ * r].level + ;
if (node[r].level & ) {
node[r].sum = node[ * r].sum | node[ * r + ].sum;
} else {
node[r].sum = node[ * r].sum ^ node[ * r + ].sum;
}
}
}
void update(int r, int p, int b) {
if (node[r].L == node[r].R) {
node[r].sum = b;
} else {
if (p <= node[ * r].R) {
// left
update( * r, p, b);
} else if (p >= node[ * r + ].L) {
// right
update( * r + , p, b);
}
if (node[r].level & ) {
node[r].sum = node[ * r].sum | node[ * r + ].sum;
} else {
node[r].sum = node[ * r].sum ^ node[ * r + ].sum;
}
}
}
} tree; int main() {
int n, m;
scanf("%d%d", &n, &m);
for (int i = ; i <= ( << n); i++) {
scanf("%d", &num[i]);
}
tree.build(, , << n);
for (int i = ; i < m; i++) {
int p, b;
scanf("%d%d", &p, &b);
tree.update(, p, b);
printf("%d\n", node[].sum);
}
}
CF339的更多相关文章
随机推荐
- CAF(C++ actor framework)(序列化之复杂类,分析 还有自己不懂的细思恐极函数实现)(三)
这里应该是序列化的最后一篇.感觉自己写的不是很好,也一点点在学习.这次就不贴上代码了.代码在github上的announce5.cpp.代码简单,但是分析下去会有细思恐极的感觉! 先看一下几个函数是干 ...
- 线程模式HS/HA和L/F的区别, HS/HA的实现原理图
线程池模式一般分为两种:L/F领导者与跟随者模式.HS/HA半同步/半异步模式. HS/HA 半同步/ 半异步模式 :分为三层,同步层.队列层.异步层,又称为生产者消费者模式,主线程处理I/O事件并解 ...
- 关联 Android 源代码 到 Ecplise
1. 下载android 源码存于本地硬盘; 2. 打开Eclpise, 新建Android Project; 3. 在MainActivity文件中,按住Ctrl 点击Activity类 4. 弹出 ...
- 单引号,双引号 和 heredoc 初始化php字符串之间的区别
php中的字符串指的是字符的序列,可以通过三种方式初始化:单引号.双引号和使用here document(heredoc) 形式. 一:单引号时 ①:需要转义的特殊字符:反斜杠和单引号. ②:因为ph ...
- PHP文件操作
1.递归获取目录下文件的个数 function getFileCount($dir){ if(!is_dir($dir)) return false; //打开目录 $handle = opendir ...
- jQuery实例—选项卡(js源码和jQuery)【一些常见方法(1)-练习】
分别利用javascript的源码和jQuery来实现一个简单的选项卡,对比各自的步骤. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Tr ...
- 使用Hibernate 拦截执行sql语句,并输出sql语句,获取sql语句
重建包名 org.hibernate.type.descriptor.sql 重建类BasicBinder 代码如下 package org.hibernate.type.descriptor.sql ...
- go语言实现线程池
话说真的好久没有写博客了,最近赶新项目,工作太忙了.这一周任务比较少,又可以随便敲敲了. 逛论坛的时候突发奇想,想用go语言实现一个线程池,主要功能是:添加total个任务到线程池中,线程池开启num ...
- GIS业务逻辑
三维怎么加载数据文件? OpenFileDialog frm = new OpenFileDialog(); frm.Filter = "文件数据集|*.tile|多时相数据集|*.Temp ...
- linux驱动系列之s3c2440内存布局
刚开始学习linux在2440上面 linux内核分配标志可以分为三类:行为修饰符.区修饰符.类型. 区修饰符表示从哪儿分配内存,内核把物理内存分为多个区,每个区用于不同的目的. 内存中缓冲区存在的原 ...