容斥原理 A Number Sequence

题意:给出n个数,b1,b2,b3……bn,构造n个数,a1,a2,……an(ai>1),使得a1*a2*a3……an=b1*b2……bn

分析:容易想到的是将bi分解质因数,然后记录每个质因数的个数。那么题目变成:对于(每个质因数个数为m个划分到n个不同的容器的方案数),注意ai>1,所以没有某个数没有质因数。记f(n)为n个数字可能有1的方案数,g(n)为n个数字一定没有1的方案数。则,得到听说这是二项式反演

#include <bits/stdc++.h>

typedef long long ll;
const int MOD = 1e9 + 7;
int b[25];
int comb[505][505];
std::vector<int> primes;
int cnt[505];
int n, tot; void init_binom() {
for (int i=0; i<=500; ++i) {
comb[i][0] = comb[i][i] = 1;
for (int j=1; j<i; ++j) {
comb[i][j] = (comb[i-1][j] + comb[i-1][j-1]) % MOD;
}
}
} void factorize(int n) {
for (int i=2; i*i<=n; ++i) {
while (n % i == 0) {
n /= i;
primes.push_back (i);
}
}
if (n > 1) {
primes.push_back (n);
}
} int get(int m, int n) {
return comb[m+n-1][n-1];
} int solve() {
int ret = 1;
for (int i=0; i<tot; ++i) {
ret = (ll) ret * get (cnt[i], n) % MOD;
}
for (int i=1; i<n; ++i) {
int tmp = 1;
for (int j=0; j<tot; ++j) {
tmp = (ll) tmp * get (cnt[j], n - i) % MOD;
}
tmp = (ll) tmp * comb[n][i] % MOD;
if (i & 1) {
ret = ((ret - tmp) % MOD + MOD) % MOD;
} else {
ret = (ret + tmp) % MOD;
}
}
return ret;
} int main() {
init_binom ();
while (scanf ("%d", &n) == 1) {
primes.clear ();
for (int i=1; i<=n; ++i) {
scanf ("%d", b+i);
factorize (b[i]);
}
std::sort (primes.begin (), primes.end ());
memset (cnt, 0, sizeof (cnt));
tot = 0;
if (!primes.empty ()) {
cnt[tot++] = 1;
}
for (int i=1; i<primes.size (); ++i) {
if (primes[i] != primes[i-1]) {
cnt[tot++] = 1;
} else {
cnt[tot-1]++;
}
}
printf ("%d\n", solve ());
}
return 0;
}

分块哈希 B Paint The Wall

题意:两种操作:1.将[l, r]区间的颜色涂成次color,2.询问[l, r]区间上color颜色的数量.(color<2^31)

分析:将n长度分块成sqrt(n)块,那么[ql, qr]的操作映射到[ql / block, qr / block]块上操作,对于(ql+block+1, qr/block)而言整块都是同一颜色,加上lazy标记,复杂度O(1),至于两端需要暴力操作,总的一次操作的复杂度为sqrt (n).还有线段树+剪枝优化(离线,颜色最大最小)也可以过,数据水.

#include <bits/stdc++.h>

const int N = 1e5 + 5;
struct Hash_Block {
int size, col;
std::map<int, int> cnt;
}hash[350];
int c[N];
int n, m, block, tot; void init_hash() {
block = (int) sqrt (n + 0.5);
tot = (n - 1) / block + 1;
for (int i=0; i<tot; ++i) {
hash[i].size = std::min (n, (i + 1) * block) - i * block;
hash[i].col = -1;
hash[i].cnt.clear ();
}
for (int i=0; i<n; ++i) {
hash[i/block].cnt[c[i]]++;
}
} void push_down(int b) {
if (hash[b].col != -1) {
hash[b].cnt.clear ();
int R = std::min ((b+1) * block, n);
for (int i=b*block; i<R; ++i) {
c[i] = hash[b].col;
hash[b].cnt[c[i]]++;
}
hash[b].col = -1;
}
} void updata(int ql, int qr, int color) {
int lb = ql / block, rb = qr / block;
for (int i=lb+1; i<rb; ++i) {
hash[i].col = color;
}
if (lb != rb) {
push_down (lb);
push_down (rb);
for (int i=ql; i<(lb+1)*block; ++i) {
hash[lb].cnt[c[i]]--;
c[i] = color; hash[lb].cnt[color]++;
}
for (int i=rb*block; i<=qr; ++i) {
hash[rb].cnt[c[i]]--;
c[i] = color; hash[rb].cnt[color]++;
}
} else {
push_down (lb);
for (int i=ql; i<=qr; ++i) {
hash[lb].cnt[c[i]]--;
c[i] = color; hash[lb].cnt[color]++;
}
}
} int query(int ql, int qr, int color) {
int lb = ql / block, rb = qr / block;
int ret = 0;
for (int i=lb+1; i<rb; ++i) {
if (hash[i].col == color) {
ret += hash[i].size;
} else if (hash[i].col == -1 && hash[i].cnt.find (color) != hash[i].cnt.end ()) {
ret += hash[i].cnt[color];
}
}
if (lb != rb) {
push_down (lb);
push_down (rb);
for (int i=ql; i<(lb+1)*block; ++i) {
ret += (c[i] == color);
}
for (int i=rb*block; i<=qr; ++i) {
ret += (c[i] == color);
}
} else {
push_down (lb);
for (int i=ql; i<=qr; ++i) {
ret += (c[i] == color);
}
}
return ret;
} int main() {
while (scanf ("%d%d", &n, &m) == 2) {
for (int i=0; i<n; ++i) {
scanf ("%d", c+i);
}
init_hash ();
for (int i=0; i<m; ++i) {
int op, ql, qr, color;
scanf ("%d%d%d%d", &op, &ql, &qr, &color);
if (op == 1) {
updata (ql, qr, color);
} else {
printf ("%d\n", query (ql, qr, color));
}
}
}
return 0;
}

暴力+贪心 D Throw nails

题意:n个人赛跑,第一秒跑f,后面每秒跑s,问每一秒跑最快的人是谁.

分析:

  方法一:考虑到f<=500,500秒前可以模拟,500秒后的状态固定了(s大的人在500秒前超过了其他人),只要sort一次就可以了.

  方法二:考虑到s<=100,对于每一个速度,设置一个优先队列保存f以及id,那么每秒跑最快的人一定是在所有速度里当前f最大中的当前最远的那个.

#include <bits/stdc++.h>

const int N = 5e4 + 5;
struct Runner {
int f, s, id;
bool dead;
bool operator < (const Runner &rhs) const {
return f > rhs.f || (f == rhs.f && id < rhs.id);
}
}r[N];
int ans[N]; int main() {
int T; scanf ("%d", &T);
for (int cas=1; cas<=T; ++cas) {
int n; scanf ("%d", &n);
int maxv = -1, maxid = -1;
for (int i=1; i<=n; ++i) {
scanf ("%d%d", &r[i].f, &r[i].s);
r[i].id = i; r[i].dead = false;
if (r[i].f > maxv) {
maxv = r[i].f;
maxid = i;
}
}
for (int i=1; i<=501; ++i) {
ans[i] = maxid;
r[maxid].dead = true;
maxv = maxid = -1;
for (int j=1; j<=n; ++j) {
r[j].f += r[j].s;
if (!r[j].dead && r[j].f > maxv) {
maxv = r[j].f;
maxid = j;
}
}
}
std::sort (r+1, r+1+n);
int m = 501;
for (int i=1; i<=n; ++i) {
if (r[i].dead) {
continue;
}
ans[++m] = r[i].id;
}
printf ("Case #%d:\n", cas);
for (int i=1; i<=n; ++i) {
printf ("%d%c", ans[i], i == n ? '\n' : ' ');
}
}
return 0;
}
#include <bits/stdc++.h>

const int N = 5e4 + 5;
struct Node {
int f, id;
bool operator < (const Node &rhs) const {
return f < rhs.f || (f == rhs.f && id > rhs.id);
}
};
std::priority_queue<Node> pque[105]; int main() {
int T; scanf ("%d", &T);
for (int cas=1; cas<=T; ++cas) {
int n; scanf ("%d", &n);
for (int i=1; i<=n; ++i) {
int f, s;
scanf ("%d%d", &f, &s);
pque[s].push ((Node) {f, i});
}
printf ("Case #%d:\n", cas);
for (int i=1; i<=n; ++i) {
int maxd = -1, minid = N, speed = 0;
for (int j=1; j<=100; ++j) {
if (!pque[j].empty ()) {
Node u = pque[j].top ();
int tf = (i-1)*j+u.f;
if (tf > maxd || (tf == maxd && u.id < minid)) {
maxd = tf;
speed = j;
minid = u.id;
}
}
}
int id = pque[speed].top ().id;
printf ("%d%c", id, i == n ? '\n' : ' ');
pque[speed].pop ();
}
}
return 0;
}

数论+BFS E Digital Square

题意:问最小的M,使得M^2%(10^x)=N

分析:这是一道数论剪枝的广搜题,如果N的最大数位是n,那么answer的最大数位应该也是n,那么可以从最小的数开始广搜,比如先确定一位数的数0,1,2…9,再在个位的基础上扩展到十位,加上0,10,20…90,然后依次下去……直到位数达到了N的位数。这里用了struct{ll a; int b;},其中a是符合要求的数,b是数位,那么剪枝的条件是a*a % 10^b == N % 10^b,证明略(可以从平方和公式入手即N^2=(X*10^m+Y)^2 N=XY(例:N=1096 X=10,Y=96 m=2或N=1096 X=109,Y=6,m=1))。最后再找出队列中剩余数的最小值即可,但要注意不满足条件的情况。

问题关键点在于N的后a位数字只由M^2后a位数字产生.

#include <bits/stdc++.h>

typedef long long ll;
const int INF = 0x7fffffff;
struct Node {
ll x;
int l;
}; int get_length(int n) {
if (n == 0) {
return 1;
}
int ret = 0;
while (n) {
ret++;
n /= 10;
}
return ret;
} ll ten_pow[12]; void prepare() {
ten_pow[0] = 1;
for (int i=1; i<12; ++i) {
ten_pow[i] = ten_pow[i-1] * 10;
}
} int BFS(int n) {
int len = get_length (n);
std::queue<Node> que; que.push ((Node) {0, 0});
ll ret = INF;
while (!que.empty ()) {
Node &u = que.front (); que.pop ();
if (u.l == len) {
ret = std::min (ret, u.x);
break;
}
for (int i=0; i<10; ++i) {
ll v = u.x + i * ten_pow[u.l];
if (v * v % ten_pow[u.l+1] == n % ten_pow[u.l+1]) {
que.push ((Node) {v, u.l + 1});
}
}
}
while (!que.empty ()) {
ll t = que.front ().x; que.pop ();
ret = std::min (ret, t);
}
return ret;
} int main() {
prepare ();
int T; scanf ("%d", &T);
while (T--) {
int n; scanf ("%d", &n);
int ans = BFS (n);
if (ans == INF) {
puts ("None");
} else {
printf ("%d\n", ans);
}
}
return 0;
}

01背包 F D-mail

题意:有n个范围在[-0.1, 2]的实数,问如何组合使得能尽可能接近范围为的实数D(-1, 2),实数小数点后有4位.

分析:数字*10^4转换为整数,D': (-10000, 20000), sum [200*-1000, 200*20000],取交集为[-200000, 20000],转化为正数,SHIFT=200000, [0, 220000]

#include <bits/stdc++.h>

const int N = 220000 + 5;
const int SHIFT = 200000;
const double EPS = 1e-8;
bool dp[N];
int a[205]; int change(double x) {
if (x > 0) {
return (int) (x * 10000 + EPS);
} else {
return (int) (x * 10000 - EPS);
}
} int main() {
int T; scanf ("%d", &T);
while (T--) {
double x;
int n, aim;
scanf ("%lf%d", &x, &n);
aim = change (x);
for (int i=0; i<n; ++i) {
scanf ("%lf", &x);
a[i] = change (x);
}
std::sort (a, a+n); memset (dp, false, sizeof (dp));
dp[0+SHIFT] = true;
for (int i=0; i<n; ++i) {
if (a[i] > 0) {
for (int j=220000-a[i]-1; j>=0; --j) {
if (dp[j]) {
dp[j+a[i]] = true;
}
}
} else {
for (int j=-a[i]; j<220000; ++j) {
if (dp[j]) {
dp[j+a[i]] = true;
}
}
}
}
double ans = 0; int now = aim + SHIFT, mv = 0;
while (true) {
if (now - mv >= 0 && dp[now-mv]) {
ans = (now - mv - SHIFT) / 10000.0;
break;
}
if (now + mv < 220000 && dp[now+mv]) {
ans = (now + mv - SHIFT) / 10000.0;
break;
}
mv++;
}
printf ("%.4f\n", ans);
}
return 0;
}

二维SPFA G More lumber is required

题意:一张有自环的有向带权图,每条边有权值,每条边能获得10木材,问从S到T所花费的最短时间,前提是木材数>=K

分析:考虑到K<=500,所以最少需要50条边.在常规的最短路最短路径加一维为边数,即d[i][j]表示走到i时走了j步最短需要的时间,当j > k时归到d[i][k]里去,这是剪枝.然后在跑一个SPFA.

对SPFA的一个很直观的理解就是由无权图的BFS转化而来。在无权图中,BFS首先到达的顶点所经历的路径一定是最短路(也就是经过的最少顶点数),所以此时利用数组记录节点访问可以使每个顶点只进队一次,但在带权图中,最先到达的顶点所计算出来的路径不一定是最短路。一个解决方法是放弃数组,此时所需时间自然就是指数级的,所以我们不能放弃数组,而是在处理一个已经在队列中且当前所得的路径比原来更好的顶点时,直接更新最优解。

#include <bits/stdc++.h>

const int N = 5e3 + 5;
const int E = 1e5 + 5;
const int INF = 0x3f3f3f3f;
struct Edge {
int v, w, nex;
}edge[E<<1];
bool vis[N][55];
int head[N], d[N][55];
int n, m, tote; struct Node{
int u, s;
}; void init(void) {
memset (head, -1, sizeof (head));
tote = 0;
} void add_edge(int u, int v, int w) {
edge[tote].v = v; edge[tote].w = w;
edge[tote].nex = head[u]; head[u] = tote++;
} void SPFA(int s, int k) {
memset (vis, false, sizeof (vis));
memset (d, INF, sizeof (d));
d[s][0] = 0; vis[s][0] = true;
std::queue<Node> que; que.push ((Node) {s, 0});
while (!que.empty ()) {
Node &r = que.front (); que.pop ();
vis[r.u][r.s] = false;
for (int i=head[r.u]; ~i; i=edge[i].nex) {
Edge &e = edge[i];
int mins = std::min (k, r.s + 1);
if (d[e.v][mins] > d[r.u][r.s] + e.w) {
d[e.v][mins] = d[r.u][r.s] + e.w;
if (!vis[e.v][mins]) {
vis[e.v][mins] = true;
que.push ((Node) {e.v, mins});
}
}
}
}
} int main() {
while (scanf ("%d%d", &n, &m) == 2) {
init ();
for (int u, v, t, i=0; i<m; ++i) {
scanf ("%d%d%d", &u, &v, &t);
add_edge (u, v, t);
add_edge (v, u, t);
}
int S, T, K; scanf ("%d%d%d", &S, &T, &K);
int k = K / 10;
if (K % 10) {
k++;
}
SPFA (S, k);
if (d[T][k] == INF) {
puts ("-1");
} else {
printf ("%d\n", d[T][k]);
}
}
return 0;
}

STL+贪心 J Template Library Management

题意:解决n个问题,解决第i个问题需要T[i]模板,手上最多只能有m块模板,问最少需要借朋友的几次.

分析:每次扔掉离下次用最远的模板,搞出每个问题的模板下次用到的时间,set维护操作,不知道为啥用pair的排序才能过.

#include <bits/stdc++.h>

const int N = 1e5 + 5;
int a[N], A[N<<1];
int pos[N<<1], nex[N], id[N];
bool ins[N<<1];
std::set<std::pair<int, int> > st;
int n, m; int main() {
while (scanf ("%d%d", &n, &m) == 2) {
int tot = 0;
for (int i=1; i<=n; ++i) {
scanf ("%d", a+i);
A[++tot] = a[i];
}
for (int i=1; i<=m; ++i) {
A[++tot] = i;
}
std::sort (A+1, A+1+tot);
tot = std::unique (A+1, A+1+tot) - (A+1);
for (int i=1; i<=tot; ++i) {
ins[i] = (i <= m);
}
for (int i=1; i<=tot; ++i) {
pos[i] = n + 1;
}
for (int i=n; i>=1; --i) {
id[i] = std::lower_bound (A+1, A+1+tot, a[i]) - A;
nex[i] = pos[id[i]];
pos[id[i]] = i;
}
st.clear ();
for (int i=1; i<=m; ++i) {
st.insert (std::make_pair (pos[i], i));
}
std::set<std::pair<int, int> >::iterator it;
int ans = 0;
for (int i=1; i<=n; ++i) {
if (ins[id[i]]) {
it = st.find (std::make_pair (pos[id[i]], id[i]));
st.erase (it);
pos[id[i]] = nex[i];
st.insert (std::make_pair (pos[id[i]], id[i]));
} else {
ans++;
ins[id[i]] = true;
pos[id[i]] = nex[i];
st.insert (std::make_pair (nex[i], id[i]));
it = st.end ();
it--;
ins[it->second] = false;
st.erase (it);
}
}
printf ("%d\n", ans);
}
return 0;
}

  

2012 Multi-University #10的更多相关文章

  1. 用Visual Studio 2012+Xamarin搭建C#开发Andriod的环境

    第一步:安装Visual Studio: Visual Studio 2012(或者Visual Studio 2010),原因是目前为止Xamarin for Visual Studio的插件只支持 ...

  2. Windows Server 2012 R2里十个极好的新功能

    Windows Server 2012 R2具备的众多新特点大大的增强了操作系统的功能性,同时也是在Windows Server 2012原有功能上的拓展.这里整理出Windows Server 20 ...

  3. SQLServer2012 和 MariaDB 10.0.3 分页效率的对比

    1. 实验环境      R910服务器, 16G内存 SqlServer 2012   64bit MariaDB 10.0.3   64bit  (InnoDB) 2. 实验表情况 rtlBill ...

  4. 解决一则enq: TX – row lock contention的性能故障

    上周二早上,收到项目组的一封邮件: 早上联代以下时间点用户有反馈EDI导入"假死",我们跟踪了EDI导入服务,服务是正常在跑,可能是处理的慢所以用户感觉是"假死" ...

  5. {ICIP2014}{收录论文列表}

    This article come from HEREARS-L1: Learning Tuesday 10:30–12:30; Oral Session; Room: Leonard de Vinc ...

  6. 探索 OpenStack 之(16):计量模块 Ceilometer 介绍及优化

    0. 背景 0.1 为什么要有 Ceilometer? 通常云,特别是公有云在计费方面有三个层次: 计量 (Metering): 收集资源的使用数据,其数据信息主要包括:使用对象(what), 使用者 ...

  7. ### Paper about Event Detection

    Paper about Event Detection. #@author: gr #@date: 2014-03-15 #@email: forgerui@gmail.com 看一些相关的论文. 1 ...

  8. 基于SpringBoot+SSM实现的Dota2资料库智能管理平台

    Dota2资料库智能管理平台的设计与实现 摘    要 当今社会,游戏产业蓬勃发展,如PC端的绝地求生.坦克世界.英雄联盟,再到移动端的王者荣耀.荒野行动的火爆.都离不开科学的游戏管理系统,游戏管理系 ...

  9. AWR之-enq TX - row lock contention的性能故障-转

    1 对这一个小时进行AWR的收集和分析,首先,从报告头中看到DB Time达到近500分钟,(DB Time)/Elapsed=8,这个比值偏高:   Snap Id Snap Time Sessio ...

  10. Compile Graphics Magick, Boost, Botan and QT with MinGW64 under Windows 7 64

    Compile Graphics Magick, Boost, Botan and QT with MinGW64 under Windows 7 64 Sun, 01/01/2012 - 15:43 ...

随机推荐

  1. 总结一下这几天学习django的心得

    总结一下这几天学习django的心得 http://www.tuicool.com/articles/jMVB3e 时间 2014-01-12 11:40:11  CSDN博客 原文  http:// ...

  2. 内嵌cuzySDK的App——礼物购已登陆App store

    内嵌cuzySDK的App——礼物购已登陆App store.每天为你搜罗特别的礼物,可分类挑选礼物,直接连接淘宝购买,做最贴心的小清新礼物助手,欢迎各位亲朋好友去下载体验.@cuzySDK  @re ...

  3. uva 11081 - Strings(LCS)

    题目链接:11081 - Strings 题目大意:给出三个字符串,从分别从第一个字符串和第二个字符串中挑选子串a,b,用a和b组成第三个字符串,问可组成的子串有多少种. 解题思路:说起来惭愧啊,题目 ...

  4. POJ 3903 Stock Exchange (E - LIS 最长上升子序列)

    POJ 3903    Stock Exchange  (E - LIS 最长上升子序列) 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action ...

  5. wamp版本升级小问题记录

    在升级wamp版本时遇到的一些小问题,特此记录 在安装完成之后,修改了Apache根目录,可以正常访问.但是发现 httpd-vhosts.conf追加配置的无法访问,逐步检查,有以下问题 1.Inc ...

  6. 老男孩python学习自修第十一天【内置函数】

    1.基本内置函数 help() 帮助文档 dir() 列出当前文件的所有变量和方法 vars() 列出当前文件的所有变量及其值 type() 返回变量的类型 id() 返回变量的内存地址 len() ...

  7. 【多媒体封装格式详解】--- AAC ADTS格式分析

    ADTS全称是(Audio Data Transport Stream),是AAC的一种十分常见的传输格式. 记得第一次做demux的时候,把AAC音频的ES流从FLV封装格式中抽出来送给硬件解码器时 ...

  8. 深度学习课程笔记(四)Gradient Descent 梯度下降算法

    深度学习课程笔记(四)Gradient Descent 梯度下降算法 2017.10.06 材料来自:http://speech.ee.ntu.edu.tw/~tlkagk/courses_MLDS1 ...

  9. 【LeetCode】207. Course Schedule (2 solutions)

    Course Schedule There are a total of n courses you have to take, labeled from 0 to n - 1. Some cours ...

  10. 【leetcode 简单】 第八十四题 两个数组的交集

    给定两个数组,编写一个函数来计算它们的交集. 示例 1: 输入: nums1 = [1,2,2,1], nums2 = [2,2] 输出: [2] 示例 2: 输入: nums1 = [4,9,5], ...