Jackiesteed

www.github.com/jackiesteed

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

00:30比赛结束,然后就是看scoreboard,acrush名副其实,开始1:07时就AK掉了.

看完board然后和MM聊,然后睡觉去,然后睡不着,然后开始写解题报告.

衣服到手,Rank555...

过掉了A和C,大数据比较给力.

A题贪心.

关键就是考虑t时间的run加速该加给哪一个时间段.

可以定性的考虑两段路程的情况,设两段路程长度都是1,不计run时速度分别是a和b,且a<b,run增加的速度为r

那么若r只能加到其中一个路程段内,应该是哪一个?

加至a,则走完两段路程需要时间1/(a +c) + 1 /b,加至b,那么需要时间 1/a + 1/ (b + c),剩下的是比较大小了,结果是加给a更优.

那么回到问题中,本题给出的是使用run加速的时间限制,但这并不能影响我们将上面的推论应用到解题中,

因为你可以假设路程长度极小,即处于一个微分的状态,这样我们从路程角度来做的分析,对于题目进行贪心就是对的.

附代码:

View Code
1 #include <iostream>
2 #include <fstream>
3 #include <cstring>
4 #include <climits>
5 #include <cstdlib>
6 #include <climits>
7 #include <cmath>
8 #include <climits>
9 #include <algorithm>
10
11  using namespace std;
12
13  const double EPS = 1e-9;
14
15 typedef pair<double , double> pii;
16
17  int X,N;
18  double t;
19 double S, R;
20 pii speed[1100000];
21
22 bool cmp(pii a, pii b)
23 {
24 return a.second < b.second;
25 }
26
27 int main()
28 {
29 freopen("A-large (3).in", "r", stdin);
30 freopen("output.out", "w", stdout);
31
32 int T;
33 scanf("%d ", &T);
34 double B,E,W;
35
36 for(int loop = 1; loop <= T; loop++)
37 {
38 scanf("%d %lf %lf %lf %d", &X, &S, &R, &t, &N);
39 double sum = 0;
40 for(int i = 0; i < N; i++)
41 {
42 scanf("%lf %lf %lf", &B, &E, &W);
43 speed[i].first = E- B;
44 speed[i].second = W;
45 sum += speed[i].first;
46 }
47
48 double x = double(X);
49 if(x - sum > 0)
50 {
51 speed[N].first = x - sum;
52 speed[N].second = 0;
53 N++;
54 }
55 double res = 0;
56 sort(speed, speed + N, cmp);
57
58 for(int i = 0; i < N; i++)
59 {
60 if(t < EPS)
61 {
62 res += (speed[i].first) / (speed[i].second + S);
63 continue;
64 }
65 if((speed[i].second + R) * t > speed[i].first)
66 {
67 res += (speed[i].first) / (speed[i].second + R);
68 t -= (speed[i].first) / (speed[i].second + R);
69 }
70 else
71 {
72 res += t;
73 speed[i].first -= t * ((speed[i].second + R));
74 t = 0;
75
76 res += speed[i].first / (speed[i].second + S);
77 }
78 }
79
80 printf("Case #%d: %0.10lf\n", loop, res);
81 }
82 return 0;
83 }

-------------------------------------------------------------------------------------------------------------------------------------

C题数论.

题目的模拟过程就是随着一个friend进入restaurant,求取一次饭店中所有人的index的lcm,如果本结果同该friend没有进入饭店时的lcm不同时,就会call一次.

那么怎样顺序进restaurant会call次数最小呢?倒着进,设a和b,a|b,那么b进入之后,得到的lcm,肯定是a的倍数,不需要call,否则,a先进,b比a多因子,这样就可能要更新

lcm,导致call,所以大数先进时call次数最少.

那么是不是小数先进call次数最多呢?U got it.究其原因,lcm为什么更新,因为进来的数带来了新的因子或是数量更多的

旧的因子(这里新的因子是原lcm没有的因子,比如进来一个7,而原lcm=8,没有7因子,更多旧因子是指,比如原lcm=8,新进来16,

则要加入一个2因子).这样小数先进,后进的大数才能每次都有可能更新lcm.

这样最朴素的算法就是按顺序不断的求lcm,但是即使小数据也会溢出,不可行.

那么我们求出最终会得到的lcm的因式分解,

lcm=(a1^e1) * (a2^e2) * ... * (an^en),

其中ai是lcm的素因子,ei是次数.理论上,每次只添加一个因子,call次数最大达到1+sigma(ai)(1<=i<=n),

实际操作是可以实现,比如10个人的case进入的序列:1,2,4,8,3,9,5,7,6,10.这里2,3,5,7,的幂由小到大依次进,剩下的数不会再更新lcm,顺序随意.

如何求lcm的因式分解呢,lcm的每一素因子的幂都小于N,(ai^ei)<=N,由N求得每个素因子及其幂即可.

当ai>sqrt(N)时,ei必然是1,不需要再求出来.

得解.

附代码:

View Code
1 #include <iostream>
2 #include <fstream>
3 #include <cstring>
4 #include <climits>
5 #include <cstdio>
6 #include <cmath>
7 #include <algorithm>
8
9 using namespace std;
10
11 typedef long long LL;
12
13 LL prime[2100000];
14 int cnt;
15 bool vis[2100000];
16 LL record[2100000];
17
18
19 LL gcd(LL a, LL b)
20 {
21 LL tmp;
22 while(b)
23 {
24 tmp = a % b;
25 a = b;
26 b = tmp;
27 }
28 return a;
29 }
30
31 LL lcm(LL a, LL b)
32 {
33 return a * b /gcd( a, b);
34 }
35
36 LL Max(LL a, LL b)
37 {
38 if(a > b)
39 return a;
40 return b;
41 }
42
43 LL Min(LL a, LL b)
44 {
45 if(a < b)
46 return a;
47 return b;
48 }
49
50 void init()
51 {
52 for(LL i = 2; i <= 1500010; i++)
53 {
54 if(vis[i])
55 continue;
56 prime[cnt++] = i;
57 for(LL j = 1; j <= 1500010 / i; j++)
58 {
59 vis[i * j] = true;
60 }
61 }
62
63 }
64
65 int main()
66 {
67 freopen("C-large (1).in", "r", stdin);
68 freopen("output.out", "w", stdout);
69 init();
70
71 int T;
72 scanf("%d", &T);
73 LL N;
74 LL a, b;
75 for(int loop = 1; loop <= T; loop++)
76 {
77 scanf("%I64d", &N);
78 if(N == 1)
79 {
80 printf("Case #%d: %I64d\n", loop, 0LL);
81 continue;
82 }
83
84 memset(record, 0, sizeof(record));
85
86 for(int i = 0; i < cnt; i++)
87 {
88 LL tmp = N;
89 while(tmp >= prime[i])
90 {
91 record[i]++;
92 tmp /= prime[i];
93 }
94 }
95 a = 1 , b= 0;
96 for(int i = 0; i < cnt; i++)
97 {
98 if(record[i])
99 {
100 a += record[i];
101 b++;
102 }
103 else
104 break;
105 }
106 LL res = a - b;
107
108 printf("Case #%d: %I64d\n", loop, res);
109 }
110
111 return 0;
112 }

posted on 2011-06-05 05:03  Jackiesteed  阅读(310)  评论(0编辑  收藏  举报