您的位置:首页 > 其它

NOIP2012提高组解题报告

2013-06-12 10:34 375 查看
Day1T1

太长了不复制了, 看这里http://wikioi.com/problem/1197/

简单的字符串替换问题.

#include <stdio.h>
#include <string.h>
char k[102], str[1002];
int main()
{
scanf("%s%s", k, str);
for (int i = 0, len = strlen(k); i < len; ++i)
if (k[i] >= 'A' && k[i] <= 'Z')
k[i] = 'a' + (k[i] - 'A');
for (int i = 0, p = 0, len = strlen(str), lenk = strlen(k); i < len; ++i, ++p, p = (p == lenk ? 0 : p))
if (str[i] >= 'A' && str[i] <= 'Z')
{
str[i] = str[i] - (k[p] - 'a');
if (str[i] - 'A' < 0)
str[i] += 26;
}
else
{
str[i] = str[i] - (k[p] - 'a');
if (str[i] - 'a' < 0)
str[i] += 26;
}
printf("%s\n", str);
return 0;
}


Day1T2

题目:http://wikioi.com/problem/1198/

给出一些二元组(Ai, Bi), 将他们按某种顺序排列. 对于每个二元组, 有一个值Fi, 计算方式是他之前所有二元组的Ai乘起来, 除以该二元组的Bi. 使得Max{F1, F2, F3 ... Fn}最小.

考虑交换相邻两个二元组的影响, 交换二元组i和二元组i+1,实际上只影响到Fi和Fi+1。

设T = A1 * A2 * ... * Ai-2 * Ai-1

方案A: Fi = T / Bi, Fi+1 =T * Ai / Bi+1

方案B: Fi = T / Bi+1, Fi+1 =T * Ai+1 / Bi

①假设1 / Bi < Ai / Bi+1, 1 / Bi+1 < Ai+1 / Bi

那么方案A优于方案B(Ai / Bi+1 < Ai+1 / Bi, Ai * Bi < Ai+1 * B i+1)

②假设1 / Bi ≥ Ai / Bi+1(Ai * Bi ≤ Bi+1)

那么1 / Bi ≤ Ai+1 / Bi, 方案A更优

③假设1 / Bi+1 ≥ Ai+1 / Bi(Ai+1 * Bi+1 ≤ Bi)

那么1 / Bi+1 ≤ Ai / Bi+1, 方案B更优

也就是说, 对于相邻两个二元组, 将A * B的较小的放在前面总能使答案更优.

实现要使用高精度, 结束.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXN 1001
struct Person
{
int a, b;
} p[MAXN];
struct High
{
int len;
int num[4001];
};
int n;
bool operator < (Person n1, Person n2)
{
return n1.a * n1.b < n2.a * n2.b;
}
bool operator > (High n1, High n2)
{
if (n1.len > n2.len)
return true;
if (n1.len < n2.len)
return false;
for (int i = n1.len - 1; i > -1; --i)
{
if (n1.num[i] > n2.num[i])
return true;
if (n1.num[i] < n2.num[i])
return false;
}
return true;
}
High operator * (High n1, int number)
{
int k = 0;
n1.len += 5;
for (int i = 0; i < n1.len; ++i)
n1.num[i] *= number;
for (int i = 0; i < n1.len; ++i)
{
n1.num[i] += k;
k = n1.num[i]/10;
n1.num[i] %= 10;
}
while (n1.num[n1.len - 1] == 0)
--n1.len;
return n1;
}
High operator / (High n1, int number)
{
High ans;
memset(ans.num, 0, sizeof ans.num);
ans.len = 0;
int now = 0;
for (int i = n1.len - 1; i > -1; --i)
{
now = now * 10 + n1.num[i];
if (now < number && ans.len == 0)
continue;
ans.num[ans.len++] = now / number;
now %= number;
}
for (int i = 0; i < ans.len / 2; ++i)
std::swap (ans.num[i], ans.num[ans.len - i - 1]);
return ans;
}
void Give(High *n1, int number)
{
memset (n1 -> num, 0, sizeof n1->num);
n1 -> len = 0;
do
{
n1 -> num[(n1 -> len)++] = number % 10;
number /= 10;
}
while (number != 0);
}
void Print(High n1)
{
for (int i = n1.len - 1; i > -1; --i)
printf("%d", n1.num[i]);
printf("\n");
}
void Init()
{
scanf("%d", &n);
for (int i = 0; i <= n; ++i)
scanf("%d %d", &p[i].a, &p[i].b);
for (int i = 1, j; i < n; ++i)
for (j = i + 1; j <= n; ++j)
if (!(p[i] < p[j]))
std::swap (p[i], p[j]);
}
int main()
{
Init();
High s, maxx;
Give(&s,p[0].a);
Give(&maxx,0);
for (int i = 1; i <= n; ++i)
{
if (s / p[i].b > maxx)
maxx = s / p[i].b;
s = s * p[i].a;
}
Print(maxx);
return 0;
}


Day1T3开车旅行

题目:http://wikioi.com/problem/1199/

对每个i点维护nextA[i], nextB[i]表示i往后A的话去哪里, B的话去哪里. 这个可以用链表来计算, 我们把所有数从小到大排序, 然后串成一个链表. 从1到n每次找Hi在链表里的前后4个判断一下, 然后把Hi从链表里删掉. 然后这样我们再用nextAB[i]表示i往后A走一次B走一次到哪里. 那么可以发现i->nextAB[i]形成了一颗树. 之后可以用树的算法做. 不过最简单的还是预处理next[i][j]表示i往后A和B都走了2^j次到哪里. 然后从大到小判2的每个次幂.

写的我太难受了, 连平时喜欢纠结的格式都没纠结成.

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <set>
using namespace std;
#define N 101000
#define L 14
#define INF 0x3f3f3f3f
const double EPS = 1e-8;
struct City
{
int h, id;
inline City(): h(0), id(0) {
}
inline City(int h, int id): h(h), id(id) {
}
inline bool operator ==(const City &p) const {
return (p.id == id);
}
}nexB
, nexA
;
struct Dist
{
int a, b, dis, id;
inline Dist(): a(0), b(0), dis(INF), id(0) {
}
inline Dist(int a, int b, int dis, int id): a(a), b(b), dis(dis), id(id) {
}
inline Dist operator +(const Dist &p) const {
return Dist(a + p.a, b + p.b, dis + p.dis, p.id);
}
}f
[L], c;
inline bool cmp1(const City &a, const City &b) {return a.h < b.h;}
inline bool cmp2(const City &a, const City &b) {return a.h > b.h;}
bool (*cp1)(const City &, const City &) = cmp1, (*cp2)(const City &, const City &) = cmp2;
set <City, bool(*)(const City &, const City &)> lr(cp1), hr(cp2);
int n, m, h
;
inline void Update(int &dis, int dis1, City &CC, set <City>::iterator iter)
{
if ((dis > dis1) || (dis == dis1 && CC.h > (iter -> h))) dis = dis1, CC = *(iter);
}
inline City nex_B(const City &now, set<City>::iterator liter, set<City>::iterator hiter)
{
City CC; int dis = INF;
int co = 1;
for (set<City>::iterator iter = liter; co <= 1 && iter != lr.end(); iter ++, co ++) Update(dis, abs(now.h - (iter -> h)), CC, iter);
co = 1;
for (set<City>::iterator iter = hiter; co <= 1 && iter != hr.end(); iter ++, co ++) Update(dis, abs(now.h - (iter -> h)), CC, iter);
if (dis == INF) return City();
return CC;
}
inline City nex_A(const City &now, set<City>::iterator liter, set<City>::iterator hiter)
{
City fir = nex_B(now, liter, hiter);
City CC; int dis = INF;
int co = 1;
for (set<City>::iterator iter = liter; co <= 2 && iter != lr.end(); iter ++, co ++) if (!((*iter) == fir)) Update(dis, abs(now.h - (iter -> h)), CC, iter);
co = 1;
for (set<City>::iterator iter = hiter; co <= 2 && iter != hr.end(); iter ++, co ++) if (!((*iter) == fir)) Update(dis, abs(now.h - (iter -> h)), CC, iter);
if (dis == INF) return City();
return CC;
}
void init()
{
scanf("%d", &n);
for (int i = 1; i <= n; i ++) scanf("%d", &h[i]);
for (int i = n; i >= 1; i --) {
lr.insert(City(h[i], i)), hr.insert(City(h[i], i));
set<City>::iterator liter = ++ lr.lower_bound(City(h[i], i)), hiter = ++ hr.lower_bound(City(h[i], i));
City j = nex_A(City(h[i], i), liter, hiter); nexA[i] = j; nexB[i] = nex_B(City(h[i], i), liter, hiter);
if (j == City()) continue ;
int a = abs(h[i] - j.h), hj = j.h, b; j = nexB[j.id];
if (j == City()) continue ; b = abs(hj - j.h);
f[i][0] = Dist(a, b, a + b, j.id);
for (int j = 1; j < L; j ++)
if (f[f[i][j - 1].id][j - 1].dis != INF) f[i][j] = f[i][j - 1] + f[f[i][j - 1].id][j - 1];
}
}
inline Dist go(int s, int x)
{
Dist CC = Dist(0, 0, 0, s);
for (int i = L - 1; i >= 0; i --)
if ((CC + f[CC.id][i]).dis <= x) CC = CC + f[CC.id][i];
City nex = nexA[CC.id];
if ((!(nex == City())) && (CC.dis + abs(h[CC.id] - nex.h) <= x)) CC = CC + Dist(abs(h[CC.id] - nex.h), 0, abs(h[CC.id] - nex.h), nex.id);
return CC;
}
void solve()
{
double CC = (double) INF;
int id = 0, x0, s, x;
bool flag = false;
scanf("%d", &x0);
for (int i = 1; i <= n; i ++) {
c = go(i, x0);
if (c.b != 0 && ((double) c.a / (double)c.b < CC || (fabs((double) c.a / (double) c.b == CC)) && h[i] > h[id])) CC = (double) c.a / (double) c.b, id = i, flag = true;
}
if (!flag) cout << hr.begin() -> id << endl; else cout << id << endl;
scanf("%d", &m);
for (int i = 1; i <= m; i ++)
scanf("%d%d", &s, &x), c = go(s, x), printf("%d %d\n", c.a, c.b);
}
int main()
{
init();
solve();
return 0;
}


Day2T1同余方程

求关于 x 同余方程 ax ≡ 1 (mod b)的最小正整数解.

一句话: 用exgcd或则利用结论a^(phi(b)-1)%b.

#include <stdio.h>
typedef long long int64;
int64 stack_k[8193];
int top = -1;
int64 extended_euclidian_algo(int64 x, int64 y)
{
int64 a = x, b = y, p, q;
while (b != 0ll)
{
stack_k[++top] = (a / b) % y;
int64 t = a % b;
a = b;
b = t;
}
p = 1ll;
q = 0ll;
while (top != -1)
{
int64 t = (p - q * stack_k[top--] % y) % y;
if (t < 0)
t += y;
p = q;
q = t;
}
return p;
}
int main()
{
int64 a, b;
scanf("%I64d %I64d", &a, &b);
scanf("%I64d\n", extended_euclidian_algo(a, b));
return 0;
}


Day2T2借教室

题目:http://wikioi.com/problem/1217/

标准解法是:让我们考虑现在有m个操作,我们先把这些操作的端点离散化一下,之后可以注意到,相邻的两个关键点之间,只有最少的哪天是有用的,那么我们可以把天数压到2m级别。然后有m个操作,我们先加入前m/2个,然后用部分和判断一下前m/2个会不会跪,会的话就在前m/2个中递归,不然就在后m/2个中递归。由于我们每次可以压天数。复杂度函数就是F(n)=n+F(n/2)=O(n).

然后我很纠结的写了个二分...

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 1004000
int a
, sum
, n, m, d
;
struct query
{
int x, y, d;
}q
;
inline int Read()
{
char ch = getchar();
while (!(ch >= '0' && ch <= '9')) ch = getchar();
int x = 0;
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
return x;
}
void init()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++) a[i] = Read();
for (int i = 1; i <= m; i ++) q[i].d = Read(), q[i].x = Read(), q[i].y = Read();//scanf("%d%d%d", &q[i].d, &q[i].x, &q[i].y);
}
bool check(int m)
{
memset(d, 0, sizeof(d));
for (int i = 1; i <= m; i ++) d[q[i].x] += q[i].d, d[q[i].y + 1] -= q[i].d;
for (int i = 1; i <= n; i ++) {
sum[i] = sum[i - 1] + d[i];
if (sum[i] > a[i]) return false;
}
return true;
}
int find(int l, int r)
{
int mid = (l + r) >> 1;
while (l <= r) {
if (check(mid)) l = mid + 1;
else r = mid - 1;
mid = (l + r) >> 1;
}
return r;
}
int main()
{
init();
int CC = find(0, m);
if (CC == m) {puts("0\n");return 0;}
printf("%d\n%d\n", -1, CC + 1);
return 0;
}


Day2T3没时间写, 改天写.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: