2016 Multi-University Training Contest 5

1001 ATM Mechine

一个人去取钱,但是他只记得金额的上限是 n ,然后他就猜每次取 y 元
如果 y > 他的存款,那么 就被警告一次,如果 y < 他的存款,就可以把这y元取出来,最多可以被警告m次.求取出存款的被警告次数的期望

自己想的时候也完全没有想到dp...枚举金额的值,瞎算..

dp[i][j] 表示 存款的上限 为 i ,还能够被警告 j 次 的期望

转移是 枚举 当前 取 k 元

如果 不被警告 ,上界从 i 变成 i-k ,此时满足的目标金额 有 i-k+1个 (就是 k 取得出来,金额 可以取 k,k+1,... ,i)

如果 被警告,上界从 i 变成 k-1 ,此时满足的目标金额有 k 个 (k 取不出来,金额可以取 0,1,2,3,...,k-1)

然后可以二分那样的去取钱,2^11 = 2024..最多11次就可以了

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <cmath>
 5 #include <algorithm>
 6 using namespace std;
 7 int n,m;
 8 const int INF = (1<<30)-1;
 9 double dp[2005][25];
10 
11 void Pre(){
12     for(int i = 0;i < 2005;i++){
13         for(int j = 0;j < 15;j++){
14             if(i == 0) dp[i][j] = 0;
15             else dp[i][j] = 1.0*INF;
16         }
17     }
18     for(int i = 1;i < 2005;i++){
19         for(int j = 1;j < 15;j++){
20             for(int k = 0;k <= i;k++){
21                 double l = (1.0*(i-k+1))/(1.0*(i+1));
22                 double r = (1.0*k)/(1.0*(i+1));
23                 dp[i][j] = min(dp[i][j],l*dp[i-k][j]+r*dp[k-1][j-1]+1);
24             }
25         }
26     }
27 }
28 
29 int main(){
30     Pre();
31     while(scanf("%d %d",&n,&m) != EOF){
32         m = min(11,m);
33         printf("%.6lf\n",dp[n][m]);
34     }
35     return 0;
36 }
View Code

 

1002 Cycle

1003 Divide the Sequence

8.14

给出 长度 为 n 的序列,问最多能够分成多少个连续的子序列,使得在这个子序列中,前缀和都是大于等于 0 的

从后往前贪心..

还纠结了下这个例子

7

2 3 -5 -5 2 2 1

为什么我的程序跑出来 是 3 ,后来发现 这个样例根本不合法= =

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 using namespace std;
 6 typedef long long LL;
 7 const int maxn = 1e6+5;
 8 int a[maxn],n;
 9 
10 void solve(){
11     LL sum = 0LL;
12     int ans = 0;
13     for(int i = n;i >= 1;i--){
14         sum += 1LL*a[i];
15         if(sum >= 0){
16             ans++;
17             sum = 0LL;
18           //  printf("i = %d ans = %d\n",i,ans);
19         }
20         //printf("i = %d sum = %I64d\n",i,sum);
21     }
22     printf("%d\n",ans);
23 }
24 
25 int main(){
26     while(scanf("%d",&n) != EOF){
27         for(int i = 1;i <= n;i++) scanf("%d",&a[i]);
28         solve();
29     }
30     return 0;
31 }
View Code

 

1004 How Many Triangles

8.16

给出 n 个点,求 锐角三角形的个数

直接统计很困难,可以转化成统计角度

锐角三角形的个数 = (锐角的个数 - 2*(钝角+直角))/3

因为 一个钝角 或者一个直角,需要消耗 两个锐角...

按理说到这里,就可以 去 补掉题了..

可是 不会极角排序,不会 two point ,不会判断 锐角,直角,钝角..还是断断续续补了好几天

----------------------昏割线---------------

其实 这道题 算原题....LA 4064 (计数 极角排序) Magnetic Train Tracks

原题不用统计直角..

先 枚举中心点

然后极角排序,因为用的是叉积,就不存在精度的问题了

然后极角排完序之后,是 成为 了一圈点

为了将环形 转化 为 线形

就把这些角 再复制 一遍

先 不太理解为什么要这样子

问司老大,举了个栗子

是为了避免 跨过 x 负半轴 的角,因为扫描 是逆时针扫的

比如 -90 ,150,其实 是存在 一个 120的钝角的

所以 变成 线性 的 -90 150 -90 150 就扫出来了

-----------------------------------------------------现在只理解了这么多..再多找两道题做做先

抄的标程的板

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <vector>
 5 #include <algorithm>
 6 using namespace std;
 7 
 8 typedef long long LL;
 9 const int maxn = 5005;
10 int n;
11 
12 struct Point {
13     int x,y;
14     Point(int _x = 0,int _y = 0) : x(_x),y(_y) {}
15     Point operator + (const Point &rhs) const {
16         return Point(x + rhs.x,y + rhs.y);
17     }
18     Point operator - (const Point &rhs) const {
19         return Point(x - rhs.x,y - rhs.y);
20     }
21     void show() const {
22         printf("%d %d\n",x,y);
23     }
24 }p[maxn];
25 
26 LL det(const Point &a,const Point &b){// 叉积
27     return a.x * 1ll * b.y - a.y * 1ll * b.x;
28 }
29 
30 LL dot(const Point &a,const Point &b){ //点积
31     return a.x * 1ll * b.x + a.y * 1ll * b.y;
32 }
33 
34 bool polar_cmp(const Point &a,const Point &b) {
35     if (a.y * 1ll * b.y <= 0) {
36         if (a.y > 0 || b.y > 0) return a.y < b.y;
37         if (a.y == 0 && b.y == 0) return a.x < b.x;
38     }
39     return det(a,b) > 0;
40 }
41 
42 LL work() {
43     LL cq = 0,cqc = 0;
44     vector<Point> vec;
45     for (int core = 0; core < n; ++core) {
46         vec.clear();
47         for (int i = 0; i < n; ++ i) {
48             if (i != core) vec.push_back(p[i] - p[core]);
49         }
50         sort(vec.begin(),vec.end(),polar_cmp);
51           vec.insert(vec.end(),vec.begin(),vec.end());//重新拷一遍角度进去,转环形为线形
52         for (int i = 0,j = 0,k = 0,r = 0; i < n - 1; ++ i) {
53             while (j < i + n - 1 && det(vec[i],vec[j]) == 0 && dot(vec[i],vec[j]) > 0) ++ j;
54             k = max(k,j);
55             while (k < i + n - 1 && det(vec[i],vec[k]) > 0 && dot(vec[i],vec[k]) > 0) ++ k;
56             r = max(r,k);
57             while (r < i + n - 1 && det(vec[i],vec[r]) > 0) ++ r;
58             cq += k - j;
59             cqc += r - k;
60         }
61     }
62     LL result = (cq - 2 * cqc) / 3;
63     //assert(result == brute());
64     return result;
65 }
66 
67 int main(){
68     while (scanf("%d",&n) != EOF){
69         for(int i = 0; i < n; ++ i){
70             scanf("%d %d",&p[i].x,&p[i].y);
71         }
72         printf("%I64d\n",work());
73     }
74     return 0;
75 }
View Code

 

 

 

1005 Interesting

1006 Interval

1007 K-wolf Number

8.13

过了这么久才来补这道题..虽然知道是数位dp

可是还是不会写

看的题解

http://111qqz.com/2016/08/hdu-5787/

给出 L,R ,k 求出 (L,R] 区间 里面 每连续 k 个数字 都不同的数的个数

dp[i][k1][k2][k3][k4] 表示 前 i 位 前 1 位 是 k1,前2位是 k2,前3位是 k3 ,前4位是 k4 的方案数

还要记录一下前导 0 的情况

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 using namespace std;
 6 typedef long long LL;
 7 LL dp[25][15][15][15][15];
 8 LL L,R;
 9 int k,d[25];
10 
11 LL dfs(int pos,int k1,int k2,int k3,int k4,int limit,int prezero){
12     if(pos == 0) return 1LL;
13     if(!prezero && !limit && ~dp[pos][k1][k2][k3][k4]) return dp[pos][k1][k2][k3][k4];
14     int top = limit?d[pos]:9;
15     LL res = 0LL;
16     if(prezero){
17         for(int i = 0;i <= top;i++){
18             res += dfs(pos-1,i,10,10,10,limit && i == top,i == 0?1:0);
19         }
20     }
21     else{
22         for(int i = 0;i <= top;i++){
23             if(k >= 2 && i == k1) continue;
24             if(k >= 3 && i == k2) continue;
25             if(k >= 4 && i == k3) continue;
26             if(k >= 5 && i == k4) continue;
27             res += dfs(pos-1,i,k1,k2,k3, limit && i == top,0);
28         }
29     }
30     if(!prezero && !limit) dp[pos][k1][k2][k3][k4] = res;
31     return res;
32 }
33 
34 LL solve(LL x){
35     memset(dp,-1LL,sizeof(dp));
36     int len = 0;
37     while(x){
38         d[++len] = x%10;
39         x = x/10;
40     }
41     LL res = dfs(len,10,10,10,10,1,1);
42     //printf("res = %I64d\n",res);
43     return res;
44 }
45 
46 int main(){
47     while(scanf("%I64d %I64d %d",&L,&R,&k) != EOF){
48         LL ans = solve(R) - solve(L-1);
49         printf("%I64d\n",ans);
50     }
51     return 0;
52 }
View Code

 

 

1008 Level Up

1009 Permutation

1010 Prefix

1011 Two

求 序列 a 和序列 b 的公告的子序列有多少个

dp[i][j] 表到 a 的 i 位置 b 的j 位置 的公告子序列的个数

dp的状态很好想,可是不会转移,

a[i] = b[j] 的时候,就会增加 dp[i-1][j-1] + 1 (加到之前的子序列里面,和自己单独成一个子序列)这个也好想..

不管相不相等的时候 都有 dp[i][j] = dp[i][j-1] + dp[i-1][j] - dp[i-1][j-1]这个不会

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 using namespace std;
 6 typedef long long LL;
 7 const int maxn = 1005;
 8 const LL mod = 1e9+7;
 9 int a[maxn],b[maxn];
10 int n,m;
11 LL dp[maxn][maxn];
12 
13 void solve(){
14     memset(dp,0LL,sizeof(dp));
15     for(int i = 1;i <= n;i++){
16         for(int j = 1;j <= m;j++){
17             if(a[i] == b[j]){
18                 dp[i][j] = (dp[i-1][j]+dp[i][j-1]+1LL)%mod;
19             }
20             else{
21                 dp[i][j] = (dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+mod)%mod;
22             }
23           //  printf("dp[%d][%d] = %d\n",i,j,dp[i][j]);
24         }
25     }
26     printf("%d\n",dp[n][m]);
27 }
28 
29 int main(){
30     while(scanf("%d %d",&n,&m) != EOF){
31         for(int i = 1;i <= n;i++) scanf("%d",&a[i]);
32         for(int i = 1;i <= m;i++) scanf("%d",&b[i]);
33         solve();
34     }
35     return 0;
36 }
View Code

 

 

1012 World is Exploding

比赛的时候想 的是 算出 所有的顺序对和逆序对,再减去不合法的三元组就可以了

但是 算 tot 的时候 用的 是 顺序对 加 逆序对来算...

而且枚举三元组的时候,只枚举到 了 a < b (c) < d  (bc重合这一种)...不知道咋想的..好菜啊..

tot = 顺*逆 再减去 四种三元组的情况

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 using namespace std;
 6 typedef long long LL;
 7 const LL mod = 1e9+7;
 8 const int maxn = 5e5+5;
 9 int a[maxn],b[maxn],lisan[maxn],c[maxn];
10 int ls[maxn],lm[maxn],rs[maxn],rm[maxn];
11 int n;
12 
13 int lowbit(int x){return x & (-x);}
14 
15 int query(int x){
16     int ret = 0;
17     while(x){
18         ret += c[x];
19         x -= lowbit(x);
20     }
21     return ret;
22 }
23 
24 void update(int x,int d){
25     while(x < maxn){
26         c[x] += d;
27         x += lowbit(x);
28     }
29 }
30 
31 void solve(){
32     memset(c,0,sizeof(c));
33     memset(ls,0,sizeof(ls));memset(lm,0,sizeof(lm));
34     memset(rs,0,sizeof(rs));memset(rm,0,sizeof(rm));
35     LL c1 = 0LL,c2 = 0LL;
36     for(int i = 1;i <= n;i++){
37         ls[i] = query(b[i]-1);
38         lm[i] = i-1 - query(b[i]);
39         update(b[i],1);
40         LL tmp = 1LL*lm[i];
41         c1 += 1LL*ls[i];
42     }
43     //for(int i = 1;i <= n;i++) printf("ls[%d] = %d lm[%d] = %d\n",i,ls[i],i,lm[i]);
44 
45     /*if(tot == 0){
46         puts("0");
47         return;
48     }*/
49     memset(c,0,sizeof(c));
50     for(int i = n;i >= 1;i--){
51         rs[i] = query(b[i]-1);
52         rm[i] = n-i - query(b[i]);
53         update(b[i],1);
54         c2 += rs[i];
55     }
56     LL tot = c1*c2;
57     //for(int i = 1;i <= n;i++) printf("rs[%d] = %d rm[%d] = %d\n",i,rs[i],i,rm[i]);
58     LL ans = 0LL;
59     for(int i = 1;i <= n;i++){
60         LL tmp = 1LL*rm[i]*rs[i] + 1LL*lm[i]*rm[i] + 1LL*ls[i]*rs[i] + 1LL*lm[i]*ls[i];
61         ans += tmp;
62     }
63     printf("%I64d\n",tot-ans);
64 }
65 
66 int main(){
67     while(scanf("%d",&n) != EOF){
68         for(int i = 1;i <= n;i++){
69             scanf("%d",&a[i]);
70             lisan[i] = a[i];
71         }
72         sort(lisan+1,lisan+n+1);
73         int cnt = unique(lisan+1,lisan+n+1) -lisan-1;
74         //for(int i = 1;i <= cnt;i++) printf("lisan[%d] = %d\n",i,lisan[i]);
75         for(int i = 1;i <= n;i++){
76             b[i] = lower_bound(lisan+1,lisan+cnt+1,a[i]) - lisan;
77         }
78         //for(int i = 1;i <= n;i++) printf("b[%d] = %d\n",i,b[i]);
79         solve();
80     }
81     return 0;
82 }
View Code

 

转载于:https://www.cnblogs.com/wuyuewoniu/p/5734975.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值