Loading

10.6 模拟赛题解报告

T1

题目描述

给定一个 \(x\),找一个最大的小于等于 \(x\) 的一个数,并且满足这个数的每一位的数是单调不降的。

\(x\leq 10^{10^5}\)

solution

直接贪心就好了,\(O(|x的位数|)\) 扫一遍序列,如果碰见不合法的就将满足条件的最后那个数第一次出现的位置 \(-1\),然后后面的数全置为 \(9\) 就好了。

复杂度 \(O(n)\)

坑点

  • 注意前导 \(0\), 给一组样例:1097

  • 不要用 \(getline\) 读入。(好多学弟好像都因为这个挂 0 了)

  • 要特判 \(0\) (众人掉坑)

/*
work by:Ariel_
Knowledge:
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
const int MAXN = 1e5 + 5;
int read(){
 int x = 0, f = 1; char c = getchar();
 while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
 while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
 return x * f;
}
int a[MAXN], n, fag, num, pre, ne, p;
char s[MAXN];
int main(){
  //freopen("increase.in", "r", stdin);
  //freopen("increase.out", "w", stdout);
  scanf("%s", s + 1);
  n = strlen(s + 1);
  if(n == 1 && a[1] == 0) {cout<<"0";return 0;}
  for (int i = 1; i <= n; i++) a[i] = s[i] - '0';
  int last = 1;
  for (int i = 2; i <= n; i++) {
	if(a[i] == a[last]) continue;
    if(a[i] > a[last]) {last = i; continue;}
	if(a[i] < a[last]) {
	  a[last]--, ne = 1, fag = last + 1;
	  break;
	}  
  }
  if(!ne) {
  	for (int i = 1; i <= n; i++) printf("%d", a[i]);
  	return 0;
  }
  for (int i = 1; i <= n; i++) {
    if(i == 1 && a[i] == 0 && last == 1) continue;
	if(i >= fag && fag && ne) cout<<9;
	else cout<<a[i];
  }
  return 0;
}

T2

题目描述

给定一个长为 \(n\) 的序列,每个数为 \(a_i\)

\(\sum_{l = 1}^{l = n}\sum_{r = l}^{r = n}\sum_{i = l}^{i = r}\sum^{r}_{j = i + 1, a_j < a_i} a_i\times a_j\)

\(n \leq 4\times 10^4, a_i \leq 10^{12}\)

solution

60pts

直接抄式子就好。

好多分哇/se

80pts

不难发现,每一个逆序对在一个区间内只会产生一次贡献,求出每个逆序对所在的区间数量,然后乘以这个逆序对的贡献就好了。

100pts

离散化,树状数组。

\(a_i, a_j\) 的贡献就是 \(a_i \times a_j \times i\times (n - j + 1)\)

移一下式子得到 \((a_i \times i)(a_j\times(n - j + 1))\)

树状数组内维护 \(a_i \times i\) ,在求逆序对的时候求一下这个玩意的和,然后乘以 \(a_j \times (n - j + 1)\) 就是 \(a_j\) 能与前面的数的逆序对产生的贡献。

龟速乘

复杂度 \(O(nlogn)\)

/*
work by:Ariel_
Knowledge:
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#define int long long
using namespace std;
const int MAXN = 1e5 + 5;
const int mod = 1e12 + 7;
int read(){
 int x = 0, f = 1; char c = getchar();
 while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
 while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
 return x * f;
}
int tree[MAXN], n, a[MAXN], tmp[MAXN], b[MAXN], Ans, cnt;
void Modify(int x, int k) {
  for (int i = x; i <= cnt; i += i & (-i)) tree[i] = (tree[i] + k) % mod;
}
int Query(int x) {
  int ret = 0;
  for (int i = x; i; i -= i & (-i)) ret = (ret + tree[i]) % mod;
  return ret;
}
int Mul(int x, int p) {
    int res = 0;
    while(p) {
        if(p & 1) res = (res + x) % mod;
        x = (x + x) % mod, p >>= 1;
    }
    return res;
}

signed main(){
  //freopen("multiplication.in", "r", stdin);
  //freopen("multiplication.out", "w", stdout);
  n = read();
  for (int i = 1; i <= n; i++) a[i] = tmp[i] = read();
  sort(tmp + 1, tmp + n + 1);
  cnt = unique(tmp + 1, tmp + n + 1) - tmp - 1;
  for (int i = 1; i <= n; i++) b[i] = lower_bound(tmp + 1, tmp + cnt + 1, a[i]) - tmp;
  for(int i = 1; i <= n; i++) {
  	 int ret = (Query(cnt) - Query(b[i]) + mod) % mod;
  	 Ans = (Ans + Mul(Mul(ret, a[i]), n - i + 1)) % mod;
  	 Modify(b[i], Mul(a[i], i));
  }
 printf("%lld\n", (Ans + mod) % mod);
  return 0;
}

T3

题目大意

给定 \(n\) 个矩形,每个矩形的左下角坐标为 \((a_i, b_i)\), 右上角的坐标为 \((c_i, d_i)\),判断这 \(n\) 个矩形是否能够恰好拼成一个大矩形,每个小矩形不重复。

\(n\leq 50000, |a_i|, |b_i|, |c_i|, |d_i| \leq 10^9\)

solution

30pts

\(n^2\)

首先所有小矩形的面积和一定等于大矩形的面积。

然后 \(n^2\) 判断每两个小矩形是否能够相互覆盖。

100pts

思路题,大的矩形内部除了四个顶点可能出现 1 个点其余地方都是 2 个或者 4 个点。

/*
work by:Ariel_
Knowledge:
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#include<map>
using namespace std;
const int INF = 1e9;
const int MAXN = 50000 + 5;
int read(){
 int x = 0, f = 1; char c = getchar();
 while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
 while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
 return x * f;
}
int n, a[MAXN], b[MAXN], c[MAXN], d[MAXN], T, Max_x = -INF, Max_y = -INF, Min_x = INF, Min_y = INF;
map<int, map<int, int> >mp;
void clear() {
  memset(a, 0, sizeof a), memset(b, 0, sizeof b);
  memset(c, 0, sizeof c), memset(d, 0, sizeof d);
  Max_x = -INF, Max_y = -INF, Min_x = INF, Min_y = INF;
}
void get(int i){
  Min_x = min(Min_x, a[i]), Max_x = max(Max_x, c[i]);
  Min_y = min(Min_y, b[i]), Max_y = max(Max_y, d[i]);
}
bool work(){
  int S = 0;
  for (int i = 1; i <= n; i++) {
  	 get(i);
  	 S += (c[i] - a[i]) * (d[i] - b[i]);
  }
  if(S != (Max_x - Min_x) * (Max_y - Min_y)) return 0;
  int num = 0;
  for (int i = 1; i <= n; i++) {
    mp[a[i]][b[i]]++, mp[a[i]][d[i]]++;
  	mp[c[i]][b[i]]++, mp[c[i]][d[i]]++;
  }
  for (int i = 1; i <= n; i++) {
  	if(mp[a[i]][b[i]] != 2 && mp[a[i]][b[i]] != 4) num++;
  	if(mp[a[i]][d[i]] != 2 && mp[a[i]][d[i]] != 4) num++;
  	if(mp[c[i]][b[i]] != 2 && mp[c[i]][b[i]] != 4) num++;
  	if(mp[c[i]][d[i]] != 2 && mp[c[i]][d[i]] != 4) num++;
  }
  return num == 4;
} 
int main(){
  T = read();
  while(T--) {
    clear();
    n = read();
    mp.clear();
    for (int i = 1; i <= n; i++) 
    a[i] = read(), b[i] = read(), c[i] = read(), d[i] = read();
    if(work()) puts("Perfect");
    else puts("Guguwansui");
  }
  return 0;
}
posted @ 2021-10-06 22:28  Dita  阅读(36)  评论(0编辑  收藏  举报