博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
2012 Multi-University #10
阅读量:6672 次
发布时间:2019-06-25

本文共 10241 字,大约阅读时间需要 34 分钟。

 

容斥原理 A 

题意:给出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 
typedef long long ll;const int MOD = 1e9 + 7;int b[25];int comb[505][505];std::vector
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
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

分块哈希 B 

题意:两种操作: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 
const int N = 1e5 + 5;struct Hash_Block { int size, col; std::map
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

 

暴力+贪心 D 

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

分析:

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

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

#include 
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 
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
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 

题意:问最小的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 
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
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 

题意:有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 
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
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 

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

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

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

#include 
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
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

 

STL+贪心 J 

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

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

#include 
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
> 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
>::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;}

  

 

转载于:https://www.cnblogs.com/Running-Time/p/5463583.html

你可能感兴趣的文章
【Python】python更新数据库脚本两种方法
查看>>
linux进程同步机制_转
查看>>
PHP框架认识初步
查看>>
给 Android 初学者的 Gradle 知识普及
查看>>
分模块开发创建Action子模块——(九)
查看>>
基于Nginx实现一个自己的HTTP模块
查看>>
LeetCode(34)-Palindrome Number
查看>>
阅读《Android 从入门到精通》(24)——切换图片
查看>>
SimpleDateFormat线程不安全及解决的方法
查看>>
Unity---------Mesh理解
查看>>
hdu 1728 逃离迷宫 bfs记转向
查看>>
一分钟学会 ConstraintLayout 之从属性角度理解布局
查看>>
线程 Timer TimerTask 计时器 定时任务 MD
查看>>
[js高手之路]原型式继承与寄生式继承
查看>>
MBR分区操作-增加、扩展、删除
查看>>
php如何互换一个数组的首尾元素 中间不变 首尾互换
查看>>
C#最简单的登录Web服务
查看>>
[Entity Framework]
查看>>
【类】C#计算器类(SamWang)
查看>>
Kinect 开发小记:穿越艾泽拉斯,调戏红龙女王
查看>>