2019.10.29 afternoon 题解报告
2019.10.29 题解报告
答题情况:
- 总成绩 : 42, 排名:
- T1 : 0 T2 : 12 T3 : 30
各题目分析:
-
题目1:
预估成绩 : 50 实际成绩 : 0 考试用时 : 1:40 ~ 2:00, 4:20 ~ 4:50开场先敲完暴力, 没有很大的感觉, 就先去看了其他题目
最后觉得唯一分解定理可做, 又看了半小时, 但是还是没有做出来
没有测给的大样例, 因为细节写炸爆了零
- 一定要注意细节, 一定要造数据卡自己!!!!
-
题目2:
预估成绩 : 20 实际成绩 : 12 考试用时 : 2:20 ~ 3:00觉得O(n^3) 的暴力DP比较好写, 就一直考虑
考虑比较长时间后, 发现不好写, 还是打了暴搜
最后复杂度过高被卡掉了8分
-
题目3:
预估成绩 : 30 实际成绩 : 30 考试用时 : 3:10 ~ 4:00直接敲了30分的暴力O(n ^ 3)
想继续优化, 觉得风险比较大
于是就去想T1
题目解析:
T1:
50 % 数据:
O(n^2) 枚举 每两个元素, 计算其gcd
取最大的gcd 的 数对的最大的lcm
总复杂度O(n ^ 2 log ai)
100 % 数据 :
发现a <= 1e6, 可以考虑枚举数
枚举 d = gcd(ai, aj) 。
只要在 a 中至少有两个数是 d 的倍数,那么 gcd(ai, aj) ≥ d
为了最大化 lcm(ai, aj),注意到 lcm(ai, aj) = aiaj / gcd(ai, aj)
只需要最大化 aiaj ——在 a 中找到是 d 的倍数的最大值 f 和次大值 g
用 fg / d 更新答案即可。
T2:
20 % 数据:
爆搜, 枚举每一个位置上的项链颜色
构造每一种合法的 项链染色方案, 并暴力统计答案
若k = 2, 则将两段分别考虑, 当第一段构造完成时, 再构造第二段, 注意重复元素
60 % 数据:
先考虑 一条项链的情况:
-
发现 一个位置的染色方案, 只与前两个位置填色有关, 满足最优子结构性质
-
则可进行DP:
设 f[i][j][k] 为: 构造到第i位, 第i-1位为j, 第i位为k 的方案数初始化 f[1][1][m] = 1;
则有状态转移方程 :
f[i][j][k] = sum(f[i-1][l][j]) (k != l && k != j) -
在得到f[n - 2][j][k] 之后,
最后两位置会与位置1 与 位置2 产生冲突,可以通过 暴力枚举 最后两位颜色, 来统计答案最后两位置 不能与 之前的会被影响的位置相同, 且不能与 开头会被影响的 位置相同
则需要四重循环 枚举 对应位置, 复杂度O(m^4)
-
由于第一位的取值有 m种, 第2位的取值有 m-1种
则最后求得答案后 要乘以 m * (m - 1)
80 % 数据:
-
对 60%数据做法 的 状态转移方程进行前缀和优化
-
将枚举最后两位置的过程 进行优化, 可以优化到O(n ^ 2). 级别
T3:
30 % 数据:
暴力枚举 被修改的塔的编号, 暴力枚举要放置的新位置
再暴力枚举 被影响的位置, 计算出其价值
取最优的最小价值即可
60 % 数据:
对于m次询问, 先将移动的信号塔(p,q) 的影响消除
枚举每一个位置的信号强度 a[i],
考虑二分答案 枚举信号强度mid
若a[i] < mid, 则i 到 q的距离不能超过 l = p - (mid - a[i])
检查q是否合法, 若q不合法, 则答案比mid小, 否则必mid 大
总复杂度O(nm log V), V是答案的范围
代码实现:
T1:
- 考场代码:
//
/*
By:Luckyblock
先暴力水一发
a <= 1e6 可以质因数分解??
*/
#include <cstdio>
#include <ctype.h>
#define max(a, b) (a > b ? a : b)
#define int long long
const int MARX = 1e6 + 10;
//=============================================================
int n, a[MARX], maxgcd, maxlcm;
//=============================================================
inline int read()
{
int s=1, w=0; char ch=getchar();
for(; !isdigit(ch);ch=getchar()) if(ch=='-') s =-1;
for(; isdigit(ch);ch=getchar()) w = (w << 1) + (w << 3) +ch-'0';
return s*w;
}
int gcd(int a1, int b) {return b ? gcd(b, a1 % b) : a1 ;}
//=============================================================
signed main()
{
freopen("gcdlcm.in","r",stdin);
freopen("gcdlcm.out","w",stdout);
n = read();
for(int i = 1; i <= n; i ++) a[i] = read();
for(int i = 1; i <= n; i ++)
for(int j = i + 1; j <= n; j ++)
{
int d = gcd(a[i], a[j]), l = a[i] / d * a[j];
if(d > maxgcd) maxlcm = l;
else if(d == maxgcd) maxlcm = max(maxlcm, l);
}
printf("%I64d", maxlcm);
}
- 正解 :
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e6;
int n, a[N + 10], cnt[N + 10];
int main() {
freopen("gcdlcm.in", "r", stdin);
freopen("gcdlcm.out", "w", stdout);
scanf("%d", &n);
int x;
for (int i = 1;i <= n;i ++) {
scanf("%d", &x);
cnt[x] ++;
}
long long ans = 1;
for (int i = 1;i <= N;i ++) {
int f = 0, g = 0;
for (int j = i;j <= N;j += i) {
if (cnt[j] > 0) {
if (cnt[j] == 1) {
g = f;
f = j;
} else {
f = g = j;
}
}
}
if (f > 0 && g > 0) {
//cout << i << " " << f << " " << g << endl;
ans = 1LL * f / i * g;
}
}
cout << ans << endl;
return 0;
}
T2:
- 考场代码:
//
/*
By:Luckyblock
*/
#include <cstdio>
#include <ctype.h>
#define int long long
const int MARX = 50;
//=============================================================
int k, n, m , p, ans, map[MARX], map1[MARX];
bool vis[MARX], vis1[MARX];
//=============================================================
inline int read()
{
int s=1, w=0; char ch=getchar();
for(; !isdigit(ch);ch=getchar()) if(ch=='-') s =-1;
for(; isdigit(ch);ch=getchar()) w = (w << 1) + (w << 3) +ch-'0';
return s*w;
}
void dfs1(int now, int last1, int last2, int sum)
{
if(now > n)
{
if(map1[n] == map1[1] || map1[n] == map1[2]) return;
if(map1[n - 1] == map1[1]) return;
ans = (ans + 1) % p;
return ;
}
for(int i = 1; i <= m; i ++)
if(i != last1 && i != last2)
if(!vis[i])
{
bool flagvis = 0;
if(!vis1[i]) sum ++, vis1[i] = 1, flagvis = 1;
map1[now] = i;
dfs1(now + 1, last2, i, sum);
if(flagvis) sum --, vis1[i] = 0;
}
}
void dfs(int now, int last1, int last2, int sum)
{
if(now > n)
{
if(map[n] == map[1] || map[n] == map[2]) return;
if(map[n - 1] == map[1]) return;
if(k == 2) dfs1(1, -1, -1, 0);
else ans = (ans + 1) % p;
return ;
}
for(int i = 1; i <= m; i ++)
if(i != last1 && i != last2)
{
bool flagvis = 0;
if(!vis[i]) sum ++, vis[i] = 1, flagvis = 1;
map[now] = i;
dfs(now + 1, last2, i, sum);
if(flagvis) sum --, vis[i] = 0;
}
}
//=============================================================
signed main()
{
freopen("necklace.in","r",stdin);
freopen("necklace.out","w",stdout);
k = read(), n = read(), m = read(), p = read();
dfs(1, -1, -1, 0);
printf("%I64d", ans);
}
- 正解 :
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 3010;
int f[2][6], c[N][N], g[N];
int calc(int n, int m, int p) {
if (n <= 4) {
int ans = 1;
for (int i = 1;i <= n;i ++) {
ans = 1LL * ans * (m - i + 1) % p;
}
return ans;
}
if (m == 3) {
return (n % 3 == 0) ? (6 % p) : 0;
}
memset(f, 0, sizeof(f));
f[1][3] = 1;
for (int i = 3;i < n - 2;i ++) {
int j = i & 1;
memset(f[j ^ 1], 0, sizeof(f[j ^ 1]));
f[j ^ 1][0] = (1LL * (m - 4) * f[j][0] + f[j][1] + f[j][3]) % p;
f[j ^ 1][1] = (1LL * (m - 3) * f[j][0] + f[j][1]) % p;
f[j ^ 1][2] = (1LL * (m - 3) * f[j][0] + f[j][3]) % p;
f[j ^ 1][3] = (1LL * (m - 3) * f[j][1] + f[j][5]) % p;
f[j ^ 1][4] = 1LL * (m - 2) * f[j][1] % p;
f[j ^ 1][5] = 1LL * (m - 2) * f[j][2] % p;
// for (int k=0;k<6;k++)
// cout << f[j^1][k]<<" ";cout << endl;
}
int aa = 1LL * (m - 2) * (m - 3) % p * ((1LL * (m - 4) * (m - 4) + m - 3) % p) % p * f[n & 1][0] % p;
int bb = 2LL * (m - 2) * (m - 3) % p * (m - 3) % p * f[n & 1][1] % p;
int cc = 1LL * (m - 2) * ((1LL * (m - 3) * (m - 3) + m - 2) % p) % p * f[n & 1][2] % p;
int dd = 1LL * (m - 2) * (m - 3) % p * (m - 4) % p * f[n & 1][3] % p;
int ee = 1LL * (m - 2) * (m - 3) % p * f[n & 1][4] % p;
int ff = 1LL * (m - 2) * (m - 3) % p * f[n & 1][5] % p;
return 1LL * m * (m - 1) % p * (1LL * aa + bb + cc + dd + ee + ff) % p;
}
int main() {
freopen("necklace.in", "r", stdin);
freopen("necklace.out", "w", stdout);
int K, n, m, p = 1000000007;
scanf("%d%d%d%d", &K, &n, &m, &p);
//scanf("%d%d", &n, &m);
for (int i = 0;i <= 3000;i ++){
c[i][0] = c[i][i] = 1;
for(int j = 1;j < i;j ++)
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % p;
}
if (K == 1) {
cout << calc(n, m, p) << endl;
return 0;
}
for (int i = 1;i <= m;i ++){
g[i] = calc(n, i, p);
}
for (int i = 1;i <= m;i ++){
for (int j = 1;j < i;j ++){
g[i] = (g[i] - 1LL * c[i][j] * g[j]) % p;
}
}
// for (int i = n + 1;i <= m;i ++)
// cout << g[i] << endl;
// cout << g[m] << endl;
int ans = 0;
for (int i = 1;i < m;i ++)
for (int j = 1;i + j <= m;j ++)
ans = (1LL * c[m][i] * c[m - i][j] % p * g[i] % p * g[j] + ans) % p;
cout << (ans + p) % p << endl;
return 0;
}
T3:
- 考场代码 :
//
/*
By:Luckyblock
*/
#include <cstdio>
#include <ctype.h>
#define max(a, b) (a > b ? a : b)
#define min(a, b) (a < b ? a : b)
#define int long long
const int MARX = 1e5 + 10;
//=============================================================
int n, m, minn, p[MARX], q[MARX], sum[MARX], sum1[MARX];
bool vis[MARX];
//=============================================================
inline int read()
{
int s=1, w=0; char ch=getchar();
for(; !isdigit(ch);ch=getchar()) if(ch=='-') s =-1;
for(; isdigit(ch);ch=getchar()) w = (w << 1) + (w << 3) +ch-'0';
return s*w;
}
int abs(int x) {return x >= 0 ? x : -x;}
//=============================================================
signed main()
{
freopen("signal.in","r",stdin);
freopen("signal.out","w",stdout);
n = read(), m = read();
for(int i = 1; i <= m; i ++) p[i] = read(), q[i] = read();
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
sum[i] += max(p[j] - abs(q[j] - i), 0);
for(int i = 1; i <= m; i ++)
{
minn = 0;
for(int j = 1; j <= n; j ++)
{
sum1[j] = sum[j];
if(max(p[i] - abs(q[i] - j), 0) > 0) sum1[j] -= (p[i] - abs(q[i] - j));
}
for(int j = 1, minnn = 1e9; j <= n; j ++, minnn = 1e9)
{
for(int k = 1; k <= n; k ++)
if(max(p[i] - abs(j - k), 0) > 0) minnn = min(minnn, sum1[k] + p[i] - abs(j - k));
else minnn = min(minnn, sum1[k]);
minn = max(minn, minnn);
}
printf("%lld\n", minn);
}
}
/*
5 3
5 2
2 5
4 1
*/
- 正解
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 100010;
const ll inf = 0x3f3f3f3f3f3f3f3fLL;
struct node {
ll v0, v1, v2, v3, v4, v5;
// 0 - max{i - a[i]}
// 1 - max{2i - a[i]}
// 2 - min{i + a[i]}
// 3 - min{a[i]}
// 4 - min{2i + a[i]}
// 5 - min{a[i]}
}seg[N * 90];
struct event {
int mask, pos;
ll v;
}e[N * 3];
int n, m, p[N], q[N], rt[N * 3], lc[N * 100], rc[N * 100], tot, etot, cnt;
ll bin[N * 3], a[N];
const node empty = (node){-inf, -inf, inf, inf, inf, inf};
int ecmp(const event &a, const event &b) {
return a.v < b.v;
}
node merge(const node &x, const node &y) {
return (node){max(x.v0, y.v0), max(x.v1, y.v1), min(x.v2, y.v2), min(x.v3, y.v3), min(x.v4, y.v4), min(x.v5, y.v5)};
}
node ask(int x, int ql, int qr, int l, int r) {
if (!x || ql > qr)
return empty;
if (ql <= l && r <= qr)
return seg[x];
int mid = (l + r) >> 1;
node ret = empty;
if (ql <= mid)
ret = merge(ret, ask(lc[x], ql, qr, l, mid));
if (mid < qr)
ret = merge(ret, ask(rc[x], ql, qr, mid + 1, r));
return ret;
}
void change(int &x, int p, int v, int mask, int l, int r) {
seg[x = ++ tot] = seg[p];
lc[x] = lc[p];
rc[x] = rc[p];
if (mask & (1 << 0)) seg[x].v0 = max(seg[x].v0, 1LL * v - a[v]);
if (mask & (1 << 1)) seg[x].v1 = max(seg[x].v1, 2LL * v - a[v]);
if (mask & (1 << 2)) seg[x].v2 = min(seg[x].v2, 1LL * v + a[v]);
if (mask & (1 << 3)) seg[x].v3 = min(seg[x].v3, a[v]);
if (mask & (1 << 4)) seg[x].v4 = min(seg[x].v4, 2LL * v + a[v]);
if (mask & (1 << 5)) seg[x].v5 = min(seg[x].v5, a[v]);
if (l == r) return;
int mid = (l + r) >> 1;
if (v <= mid)
change(lc[x], lc[p], v, mask, l, mid);
else
change(rc[x], rc[p], v, mask, mid + 1, r);
}
int check(int x, ll mid) {
int pp = p[x], qq = q[x], st, ed, z;
ll l = 1, r = n;
node t;
st = max(qq - pp + 1, 1);
ed = min(qq + pp - 1, n);
z = lower_bound(bin + 1, bin + cnt + 1, mid) - bin - 1;
if (z > 0) {
if (st > 1) {
t = ask(rt[z], 1, st - 1, 1, n);
l = max(l, t.v0 - pp + mid);
r = min(r, t.v2 + pp - mid);
}
if (ed < n) {
t = ask(rt[z], ed + 1, n, 1, n);
l = max(l, t.v0 - pp + mid);
r = min(r, t.v2 + pp - mid);
}
}
z = lower_bound(bin + 1, bin + cnt + 1, mid + pp - qq) - bin - 1;
if (z > 0) {
if (st <= qq) {
t = ask(rt[z], st, qq, 1, n);
l = max(l, t.v1 + mid - qq);
r = min(r, t.v3 - mid + qq);
}
}
z = lower_bound(bin + 1, bin + cnt + 1, mid + pp + qq) - bin - 1;
if (z > 0) {
if (qq < ed) {
t = ask(rt[z], qq + 1, ed, 1, n);
l = max(l, -t.v5 + mid + qq);
r = min(r, t.v4 - mid - qq);
}
}
return l <= r;
}
int main() {
freopen("signal.in", "r", stdin);
freopen("signal.out", "w", stdout);
seg[0] = empty;
scanf("%d%d", &n, &m);
for (int i = 1;i <= m;i ++) {
scanf("%d%d", &p[i], &q[i]);
int st = max(q[i] - p[i] + 1, 1);
int v = p[i] - abs(q[i] - st);
int ed = min(q[i] + p[i] - 1, n);
a[st] += v;
a[st + 1] += 1 - v;
a[q[i] + 1] += -2;
a[ed + 2] += 1;
}
for (int i = 0;i < 2;i ++)
for (int j = 1;j <= n;j ++)
a[j] += a[j - 1];
for (int i = 1;i <= n;i ++) {
bin[++ cnt] = a[i];
bin[++ cnt] = a[i] - i;
bin[++ cnt] = a[i] + i;
e[++ etot] = (event){1 | 4, i, a[i]};
e[++ etot] = (event){2 | 8, i, a[i] - i};
e[++ etot] = (event){16 | 32, i, a[i] + i};
}
sort(e + 1, e + etot + 1, ecmp);
sort(bin + 1, bin + cnt + 1);
cnt = unique(bin + 1, bin + cnt + 1) - bin - 1;
int cur = 0;
for (int i = 1;i <= cnt;i ++) {
rt[i] = rt[i - 1];
while (cur + 1 <= etot && e[cur + 1].v == bin[i]) {
change(rt[i], rt[i], e[cur + 1].pos, e[cur + 1].mask, 1, n);
cur ++;
}
}
ll l, r, mid;
for (int i = 1;i <= m;i ++) {
l = 0;
r = 10000000000LL;
while (l <= r){
mid = (l + r) >> 1;
if (check(i, mid))
l = mid + 1;
else
r = mid - 1;
}
printf("%lld\n", r);
}
return 0;
}