“玲珑杯”ACM比赛 Round #18 A 前缀预处理 D dp

DESCRIPTION

今天HHHH 考完了期末考试,他在教学楼里闲逛,他看着教学楼里一间间的教室,于是开始思考:

如果从一个坐标为 (x1,y1,z1)(x1,y1,z1) 的教室走到(x2,y2,z2)(x2,y2,z2) 的距离为 |x1x2|+|y1y2|+|z1z2||x1−x2|+|y1−y2|+|z1−z2|

那么有多少对教室之间的距离是不超过RR 的呢?

INPUT
第一行是一个整数T(1T10)T(1≤T≤10) , 表示有TT 组数据 接下来是TT 组数据,对于每组数据: 第一行是两个整数n,q(1n5×104,1q103)n,q(1≤n≤5×104,1≤q≤103) , 表示有nn 间教室, qq 次询问. 接下来是nn 行, 每行3个整数xi,yi,zi(0xi,yi,zi10)xi,yi,zi(0≤xi,yi,zi≤10) ,表示这间教室的坐标. 最后是qq 行,每行一个整数R(0R109)R(0≤R≤109) ,意思见描述.
OUTPUT
对于每个询问RR 输出一行一个整数,表示有多少对教室满足题目所述的距离关系.
SAMPLE INPUT
1 3 3 0 0 0 1 1 1 1 1 1 1 2 3
SAMPLE OUTPUT
1 1 3
HINT
对于样例,1号教室和2号教室之间的距离为3, 1号和3号之间的距离为3, 2号和3号之间的距离为0
SOLUTION
题解:考虑到坐标的范围非常小,我们可以统计每一个点有多少个教室,然后枚举坐标预处理答案,然后做一个前缀和即可

要小心的是R的范围  注意乘的时候会爆int

 1 #pragma comment(linker, "/STACK:102400000,102400000")
 2 #include <cstdio>
 3 #include <iostream>
 4 #include <cstdlib>
 5 #include <cstring>
 6 #include <algorithm>
 7 #include <cmath>
 8 #include <cctype>
 9 #include <map>
10 #include <set>
11 #include <queue>
12 #include <bitset>
13 #include <string>
14 #include <complex>
15 #define ll long long
16 using namespace std;
17 int t;
18 int n,q;
19 int mp[15][15][15];
20 int x[50004],y[50004],z[50004];
21 int s[50004];
22 ll sum[505];
23 int main()
24 {
25     scanf("%d",&t);
26     for(int i=1;i<=t;i++)
27     {
28         for(int j=0;j<=10;j++)
29             for(int l=0;l<=10;l++)
30              for(int k=0;k<=10;k++)
31                mp[j][l][k]=0;
32         for(int j=0;j<=50;j++)
33             sum[j]=0;
34         scanf("%d %d",&n,&q);
35         int jishu=0;
36         for(int j=1;j<=n;j++)
37         {
38             scanf("%d %d %d",&x[j],&y[j],&z[j]);
39             if(mp[x[j]][y[j]][z[j]]==0)
40                 s[jishu++]=j;
41             mp[x[j]][y[j]][z[j]]++;
42       }
43         for(int j=0;j<jishu;j++)
44         {
45             for(int k=j;k<jishu;k++)
46             {
47                 if(j==k)
48                 {
49                     ll now=mp[x[s[j]]][y[s[j]]][z[s[j]]];
50                     sum[0]+=now*(now-1)/2;
51                 }
52                 else{ 
53  int dis=abs(x[s[j]]-x[s[k]])+abs(y[s[j]]-y[s[k]])+abs(z[s[j]]-z[s[k]]);
54   sum[dis]+=mp[x[s[k]]][y[s[k]]][z[s[k]]]*mp[x[s[j]]][y[s[j]]][z[s[j]]];
55                 }
56             }
57         }
58         for(int j=1;j<=50;j++)
59             sum[j]+=sum[j-1];
60         int exm;
61         for(int j=1;j<=q;j++)
62         {
63             scanf("%d",&exm);
64             if(exm>50)
65                 printf("%lld
",sum[50]);
66             else
67                 printf("%lld
",sum[exm]);
68         }
69     }
70     return 0;
71 }
DESCRIPTION

今天HHHH 在操场上跑步,HHHH 作为一个爱运动的人,肯定会想方设法把跑步所消耗的能量减到最少.

现在这个操场上有nn 个可以休息的点,他们的坐标分别为x1,x2...xn(xixi+1)x1,x2...xn(xi≤xi+1) ,HHHH 刚开始在 x1x1 ,并且他只能在这些点休息,在中途不能停下来,否则会因为旁边的音浪太强而被晃到.

如果HHHH 连续跑一段长度为ll 的距离,那么他将会消耗2l+a2l+a 的能量(aa 为HHHH 的可爱值)

现在给你这些点的坐标,请帮HHHH 计算他跑到xnxn 点所需要消耗的能量最少是多少.

INPUT
第一行是一个整数T(1T10)T(1≤T≤10) ,表示有TT 组数据 对于每组数据输入一行2个整数n,a (1n105,1a106)n,a (1≤n≤105,1≤a≤106) 表示总共有nn 个休息点,HHHH 的可爱值为aa . 接着一行nn 个数x1,x2...,xn(0xi3×106,0xi+1xi30)x1,x2...,xn(0≤xi≤3×106,0≤xi+1−xi≤30) ,表示点的位置.
OUTPUT
每组数据输出一行,一个整数,表示最小需要花费的体力
SAMPLE INPUT
2 3 2 3 5 7 3 10 3 5 7
SAMPLE OUTPUT
12 26
HINT
对于第一组样例,最少的体力消耗是先从3跑到5,消耗6点体力,再从5跑到7,消耗6点体力,共12点 对于第二组样例,最少的体力消耗是直接从3跑到7,消耗26点体力.
题解:

首先我们可以想到一个简单的dp方程

dp[i]=min(dp[j]+2^(dis[i]dis[j]))+a

1.然后我们发现这个2^x很快就会比a 高到不知道哪里去,所以当这个距离超过一定值的时候肯定是分开

跑比较划算了,所以我们只需要枚举当前点前面的几十个点再转移一下就行了

2.我们也可以简单的推导一下发现这个dp方程是决策性单调的所以你懂的

 1 #pragma comment(linker, "/STACK:102400000,102400000")
 2 #include <cstdio>
 3 #include <iostream>
 4 #include <cstdlib>
 5 #include <cstring>
 6 #include <algorithm>
 7 #include <cmath>
 8 #include <cctype>
 9 #include <map>
10 #include <set>
11 #include <queue>
12 #include <bitset>
13 #include <string>
14 #include <complex>
15 #define ll long long
16 using namespace std;
17 int t;
18 int aa[100005];
19 int b[100005];
20 ll dp[3000006];
21 map<int,int>mp;
22 int n,a;
23 int main()
24 {
25     scanf("%d",&t);
26     int ans=0;
27     for(int j=1;j<=t;j++)
28     {
29         scanf("%d %d",&n,&a);
30         int jishu=0;
31         mp.clear();
32         for(int i=1;i<=n;i++){
33             scanf("%d",&aa[i]);
34             if(mp[aa[i]]==0){
35                 b[jishu++]=aa[i];
36                 mp[aa[i]]=1;
37             }
38             }
39         sort(b,b+jishu);
40         for(int i=0;i<jishu;i++){
41             dp[i]=1e18+1;
42             }
43         dp[0]=0;
44         for(int i=1;i<jishu;i++)
45         {
46             for(int j=i-1;j>=0;j--)
47             {
48                 if(b[i]-b[j]>30)
49                     break;
50                 dp[i]=min(dp[i],dp[j]+(1ll<<(b[i]-b[j]))+a);
51             }
52         }
53         printf("%lld
",dp[jishu-1]);
54     }
55     return 0;
56 }
原文地址:https://www.cnblogs.com/hsd-/p/7184079.html