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 % 数据:

  1. 对 60%数据做法 的 状态转移方程进行前缀和优化

  2. 将枚举最后两位置的过程 进行优化, 可以优化到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;
}
posted @ 2019-10-29 20:58  Luckyblock  阅读(180)  评论(0编辑  收藏  举报