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 }
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 }
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 }
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 }
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 }
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 }