T1
题目大意:
跳楼: 起跳准备需要花费, 楼之间的高度差也需要花费.
求在给定花费下, 最多可以跳几栋楼
简单分析:
不难发现, 跳楼过程中楼房的高度具有单调性
这样的性质为dp的转移提供了明确的方向
标算:
状态: dp[i][j]表示跳到了第i栋楼,跳了j次的最小花费
转移: 枚举下一次跳到哪个楼上
答案: 枚举所有可能的状态, 将花费满足条件的计入答案即可
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 55;
int n, t, dp[N][N];
//dp[i][j]表示跳到了第i栋楼,跳了j次的最小花费
struct building {
int c, h;
}b[N];
bool cmp(building a, building b) {return a.h < b.h;}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; ++i) scanf("%d", &b[i].c);
for(int i = 1; i <= n; ++i) scanf("%d", &b[i].h);
scanf("%d", &t);
sort(b+1, b+n+1, cmp);
memset(dp, 0x3f, sizeof(dp));
dp[1][1] = b[1].c;
for(int i = 1; i <= n; ++i) { //现在在第i栋楼上
for(int j = 1; j <= n; ++j) { //跳了j次
for(int l = i+1; l <= n; ++l) { //下一次跳到第l栋楼上
dp[l][j+1] = min(dp[l][j+1], dp[i][j]+b[l].h-b[i].h+b[l].c);
}
}
}
int ans = 0;
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= n; ++j) {
if(dp[i][j] <= t) { //统计答案
ans = max(ans, j);
}
}
}
printf("%d\n", ans);
return 0;
}
T2
题目大意:
有n个数, 给出他们的和(共n*(n-1)/2个)求这n个数, 按字典序输出
简单分析:
另a1,a2,……,an为一组答案,那么给出的n* (n-1)/2个数中,最小的一定等于a1+a2,次小的一定等于a1+a3,为了确定a1 a2 a3我们还需要a2+a3的值。由于a1+a4可能小于a2+a3,所以我们不能确定a2+a3的值,那么由于数据范围挺小的,枚举a2+a3是n* (n-1)/2中的哪一个就好了。确定了a2+a3之后我们发现a1 a2 a3的值就都有了,然后a1+a4一定是剩下中最小的,依次类推一个一个解出剩下的数就搞定了。
标算:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 310;
int n, m, res[N], ans[N][N], a[N*N], cnt;
bool use[N*N];
void check(int x) {
memset(use, false, sizeof(use));
if((a[1]+a[2]+a[x])&1) return;
res[1] = (a[1]+a[2]+a[x])/2 - a[x];
res[2] = a[1] - res[1];
res[3] = a[2] - res[1];
use[1] = use[2] = use[x] = true;//确定前三个
for(int i = 4, j = 3; i <= n; ++i) {
while(j <= m && use[j]) j++;
if(j > m) return;
res[i] = a[j] - res[1];
use[j] = true;
for(int k = 2; k < i; ++k) {
if(res[k] > res[i]) return;
int v = res[k] + res[i];
int p = lower_bound(a+1, a+m+1, v) - a;
if(a[p] != v) return;
int px = p;
while(px && a[px] == a[p]) px--;
px++;
while(px <= m && a[px] == a[p] && use[px]) px++;
if(a[px] != a[p] || use[px]) return;
p = px;
use[p] = true;
}
}
cnt++;
for(int i = 1; i <= n; ++i) {
ans[cnt][i] = res[i];
}
}
int main() {
scanf("%d", &n);
m = n*(n-1)/2;
for(int i = 1; i <= m; ++i) scanf("%d", &a[i]);
sort(a+1, a+m+1);
for(int i = 3; i <= m;) { //枚举哪一个是a2+a3
check(i);
int j = i;
while(j <= m && a[j] == a[i]) j++;
i = j;
}
printf("%d\n", cnt);
for(int i = 1; i <= cnt; ++i) {
for(int j = 1; j <= n; ++j) {
printf("%d", ans[i][j]);
if(j == n) printf("\n");
else printf(" ");
}
}
return 0;
}
T3
不可做的题目大意:
每个街灯上都有一个数,每次询问,第��个街灯到第��个街灯上的数模��等于��的有几个
用命分析:
做法的核心思想是按p的大小分不同的做法,首先注意到p>10000是没有什么意义的,所以我们按照sqrt(10000)=100进行分块来做。
咋都看不懂的标算:
对于p<=100的,我们发现对于p<=100,总共的可能的询问也就只有100*(100-1)/2=4950种(p,v)的取值,所以我们可以预处理这一部分。我们枚举一个p和一个v,对一个(p,v)开一个vector,将所有模p等于v的数全部放到这个vector里面来,那么每次询问的时候,只需要直接在这个vector里面二分区间内有多少个在这个vector里面即可。
对于p>100的,情况就比较多了没法预处理了,但是注意到可能被统计到答案里面的数,只有v,p+v,2p+v…………之类的数,这样可能的数只有sqrt(n)个,所以我们提前对每一个v开一个vector,把所有等于v的数全部放到这个vector里面。之后每一次询问的时候,我们去v,p+v,2p+v……这每一个vector里面二分即可。
这样总的复杂度就是O(nlognsqrt(n))了,就可以过了。vector常数比较大我也不知道能不能过,不过这个也可以直接用数组或者链表实现。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 100009;
const int maxv = 10000;
const int bsz = 100;
const int maxb = 103;
int n, m;
int a[maxn], vb[maxb][maxb], ve[maxb][maxb];
int xb[maxn], xe[maxn];
int i_buf[maxn * maxb * 2], tib;
void pre() {
memset(ve, 0, sizeof(ve));
memset(xe, 0, sizeof(xe));
for (int i = 1; i <= n; ++ i)
++ xe[a[i]];
for (int i = 0; i <= maxv; ++ i) {
xb[i] = tib;
tib += xe[i];
xe[i] = xb[i];
}
for (int i = 1; i <= n; ++ i)
i_buf[xe[a[i]] ++] = i;
for (int m = 1; m <= bsz; ++ m) {
for (int i = 1; i <= n; ++ i)
++ ve[m][a[i] % m];
for (int i = 0; i < m; ++ i) {
vb[m][i] = tib;
tib += ve[m][i];
ve[m][i] = vb[m][i];
}
for (int i = 1; i <= n; ++ i)
i_buf[ve[m][a[i] % m] ++] = i;
}
}
int queryb(int l0, int r0, int p, int k) {
if (vb[p][k] == ve[p][k])
return 0;
int *x1 = lower_bound(i_buf + vb[p][k], i_buf + ve[p][k], l0);
int *x2 = upper_bound(i_buf + vb[p][k], i_buf + ve[p][k], r0);
return x2 - x1;
}
int querys(int v, int l0, int r0) {
if (xb[v] == xe[v])
return 0;
int *x1 = lower_bound(i_buf + xb[v], i_buf + xe[v], l0);
int *x2 = upper_bound(i_buf + xb[v], i_buf + xe[v], r0);
return x2 - x1;
}
int querya(int l0, int r0, int p, int k) {
int ans = 0;
for (int i = k; i <= maxv; i += p)
ans += querys(i, l0, r0);
return ans;
}
int main() {
scanf("%d%d", &n, &m);
tib = 0;
for (int i = 1; i <= n; ++ i)
scanf("%d", a + i);
pre();
while (m --) {
int l, r, p, k;
scanf("%d%d%d%d", &l, &r, &p, &k);
if (p <= bsz)
printf("%d\n", queryb(l, r, p, k));
else
printf("%d\n", querya(l, r, p, k));
}
}