目录

noip模拟6

目录

挂分之神

T1

考场上是这么想的:先按x从小到大,再按y从小到大排序,然后从后往前枚举长方形看是否相邻,然后因为x和y越往前越小,所以可以剪枝。code

排完序的图片 /images/noip6/1.png /images/noip6/2.png

然而,这种做法有一个大问题,就是随着i的增大,枚举的长方形数也会增大,而且我还是用枚举边框上的元素的方式来更新的结果,所以就出现了 $ {\color{Orange} \mathsf{TLE}} $ 然后在调代码时给我来了个这/images/noip6/wtftle.png

emmm……既然从后往前不行那就从前往后,Nie!然后因为x随i(编号)增大而单调递增,所以对于水平方向来说只用看y,而竖直方向上只要x[j]=x[i]+1就可以转移,而且知道一个长方形内氢键的个数即为 $ (x_j - x_i)*(y_j - y_i) * 2 $ 那就好办了。

对于水平方向来说只用判断下一个长方形是否满足 $ y_j1 = y_x2+1 $ 或 $ y_j2 + 1 = y_x1 $ (分别对应上和下) 但还要注意若 $ x_i1=x_j1 $ (对x2同理)是要把ans-1(因为是斜线),竖直方向同理

code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <bits/stdc++.h>
#define TO_BE_CONTINUED continue
using namespace std;
const int maxn(100010);

int n;
unsigned long long tot;
struct SQU {
  long long x1, y1, x2, y2;
} sq[maxn];
bool cmp(SQU a, SQU b) {
  if (a.x1 == b.x1) return a.y1 < b.y1;
  return a.x1 < b.x1;
}
int main() {
  // freopen("1.in", "r", stdin);
  scanf("%d", &n);
  for (int i = 1; i <= n; i++) {
    scanf("%lld%lld%lld%lld", &sq[i].x1, &sq[i].y1, &sq[i].x2, &sq[i].y2);
  }
  sort(sq + 1, sq + 1 + n, cmp);
  for (int i = 1; i <= n; i++) {
    tot += (sq[i].x2 - sq[i].x1) * (sq[i].y2 - sq[i].y1) * 4;
  }
  for (int i = 1; i <= n; i++) {
    if (n == 1) {
      cout << tot / 2 << endl;
      return 0;
    }
    for (int j = i + 1; j <= n; j++) {
      bool flagh = 0, flagv = 0;
      if (sq[j].x1 - sq[i].x2 > 1) break;
      if (sq[j].y1 - sq[i].y2 > 1) continue;
      if (sq[i].y1 - sq[j].y2 > 1) continue;
      if (sq[i].y2 + 1 == sq[j].y1 || sq[j].y2 + 1 == sq[i].y1) {  // horizontal
        if (sq[j].x1 == sq[i].x2 + 1) {
          tot += 2;
          TO_BE_CONTINUED;
        }
        tot += 4 * (min(sq[i].x2, sq[j].x2) - sq[j].x1 + 1);
        if (sq[i].x1 == sq[j].x1) tot -= 2;
        if (sq[i].x2 == sq[j].x2) tot -= 2;
      }
      if (sq[i].x2 + 1 == sq[j].x1) {  // vertical
        tot += 4 * (min(sq[i].y2, sq[j].y2) - max(sq[j].y1, sq[i].y1) + 1);
        if (sq[i].y1 == sq[j].y1) tot -= 2;
        if (sq[i].y2 == sq[j].y2) tot -= 2;
      }
    }
  }
  cout << tot / 2 << endl;
  return 0;
}

T2 我不会

pyt会讲

T3

考场思路:想到了与正解挺像的方法,并且在n%k==0时对了,因为脑子混乱而爆了个大零蛋

正解:cbx的神奇解法,因为题目中说按最大的数计算劳累程度,所以要想得到一个小数,那么这种情况一定全是小数。举个例子:如果m=3,想得到1,那么在每一位上都有 $ \frac{1}{m} $ 的几率是1,一共有K位,那么就有 $ (\frac{1}{m} )^2 $ 的几率结果得到1。如果想得到2,那么这个组合中只要有2就OK,所以概率为 $ \frac{2}{3} $ ,这种情况还包含了第一种为1的情况,所以最后还要减去它

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <bits/stdc++.h>
using namespace std;
const long long maxn = 1001, MOD = 1000000007;
long long qpow(long long base, long long power, long long mod) {
  if (power == 0) return 1;
  long long ans = 1;
  while (power) {
    if (power & 1) {
      ans = 1ll * ans * base % mod;
    }
    base = 1ll * (1ll * base * base) % mod;
    power >>= 1;
  }
  return ans;
}

long long n, m, k, fm, fz, fminv, ans;
long long w, franc[maxn], po[maxn];  //函数值 和 概率
int main() {
  cin >> n >> m >> k;
  fm = qpow(m, k, MOD);
  fminv = qpow(fm, MOD - 2, MOD);
  for (long long i = 1; i <= m; i++) {
    po[i] = (qpow(i, k, MOD) * fminv) % MOD;
    franc[i] = (po[i] - po[i - 1] + MOD) % MOD;
    cin >> w;
    ans = (ans + franc[i] * w % MOD) % MOD;
  }
  if (k > n) {
    cout << "0" << endl;
    return 0;
  }
  ans = ans * (n - k + 1) % MOD;
  cout << ans << endl;
  return 0;
}

T4

蓝书上有讲解,没啥好说的,代码我也码不对,Github上也有标程,不放了 (PS:括号挺多,别打错了)