2020.9.6 解题报告

2020.9.6


\[\text{完全憑依!} \]

\[\text{By:Th15.5Block} \]


答题情况

总成绩 : 150 , 排名 : 5 / 6
T1 : 100 T2 : 20 T3 : 30

各题目分析

题目 1 :
预估成绩 : 100 实际成绩 : 100 考试用时 : 8:00 ~ 8:20

签到题。

题目 2 :
预估成绩 : 100 实际成绩 : 20 考试用时 : 8:20 ~ 9:00,10:00 ~ 11:00

先写了 \(O(n^3\log m)\) 的暴力,卡常卡到 2.4s 想出正解。
写完正解扔了,最后 FST 了。

错了两个边界问题,写完代码后一定通读前文检查!

题目 3 :
预估成绩 : 0 实际成绩 : 30 考试用时 : 9:00 ~ 10:00,11:00 ~ 11:30

一开始就觉得不可做,弃了,写了贪心。


题目解析

T1

将 n 个串中相同位置的 0/1 的数量记录下来。
贪心的找每一位数量较少的数字即可。


T2

二分最小的长度,DP 检查。
\(f_{i,j}\) 表示使用了 \(i\) 次红,\(j\) 次绿后,能覆盖到的最远的法坛的位置。
DP 方程:

\[f_{i,j} = \max\{\operatorname{red\_next}(f_{i-1,j}), \operatorname{green\_next}(f_{i,j-1})\} \]

\(\operatorname{red\_next}(x)\) 表示从 \(x\) 开始,使用一次红光,能覆盖到的最远的右侧的法坛,\(\operatorname{green\_next}\) 同理。
上述两值可以通过二分获得,也可以直接 \(O(n^2)\) 预处理。

最后检查能否覆盖到 \(n\) 即可,预处理后复杂度 \(O(n^2\log m)\)\(m\) 为答案最大值)。


T3

要求次短路,先求出最短路。
设到达节点 \(x\) 的最短路长为 \(s1\), 与结点 \(x\) 相连的最短边长度为 \(c\)
\(s2=s1+2\times c\)\(s2\) 即为次短路长度的上界。
DFS,搜索过程中利用 \(s2\) 进行剪枝,不断更新 \(s2\)
可以证明每个节点被到达不超过 \(n\) 次。


代码实现

T1 :

考场代码

//
/*
By:Luckyblock
*/
#include <algorithm>
#include <cstdio>
#include <ctype.h>
#include <cstring>
#define ll long long
const int kMaxn = 1010;
//=============================================================
int n, l, cnt[kMaxn][2];
char s[kMaxn];
//=============================================================
inline int read() {
  int f = 1, w = 0; char ch = getchar();
  for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
  for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
  return f * w;
}
//=============================================================
int main() {
  freopen("curse.in", "r", stdin);
  freopen("curse.out", "w", stdout);
  n = read();
  for (int i = 1; i <= n; ++ i) {
    scanf("%s", s + 1);
    l = strlen(s + 1);
    for (int i = 1; i <= l; ++ i) {
      cnt[i][s[i] == '1'] ++; 
    }
  }
  for (int i = 1; i <= l; ++ i) {
    printf("%d", cnt[i][1] > cnt[i][0]);
  }
  return 0;
}

T2:

考场代码

//
/*
By:Luckyblock
*/
#include <algorithm>
#include <cstdio>
#include <ctype.h>
#include <cstring>
#define ll long long
const int kMaxn = 2000 + 10;
const int kInf = 1e9 + 10; 
//=============================================================
int n, r, g, a[kMaxn];
int f[kMaxn][kMaxn];
//=============================================================
inline int read() {
  int f = 1, w = 0; char ch = getchar();
  for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
  for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
  return f * w;
}
void GetMax(int &fir, int sec) {
  if (sec > fir) fir = sec;
}
int Query(int pos_, int val_) {
  int l = pos_ + 1, r = n, ret;
  while (l <= r) {
    int mid = (l + r) >> 1;
    if (a[mid] - a[pos_ + 1] <= val_) {
      ret = mid;
      l = mid + 1;
    } else {
      r = mid - 1;
    }
  }
  return ret;
}
void koishi() {
  int satoti;
}
bool Check(int l_) {
  bool ret = false;
  memset(f, 0, sizeof (f));
  f[0][0] = - 1;
  for (int i = 0; i <= r; ++ i) {
    for (int j = 0; j <= g; ++ j) {
      if (i) GetMax(f[i][j], Query(f[i - 1][j], l_));
      if (j) GetMax(f[i][j], Query(f[i][j - 1], 2 * l_));
      if(f[i][j] >= n) ret = true;
    }
  }
  return ret;
}
//=============================================================
int main() {
  freopen("light.in", "r", stdin);
  freopen("light.out", "w", stdout);
  n = read(), r = read(), g = read();
  if (r + g >= n) {
    printf("1\n");
    return 0;
  }
  for (int i = 1; i <= n; ++ i) a[i] = read();
  std :: sort(a + 1, a + n + 1);
  int l = 2; 
  int r = a[n] / (r + g);
  int ans = a[n] / (r + g);
  while (l <= r) {
    int mid = (l + r) >> 1;
    if (Check(mid)) {
      ans = mid;
      r = mid - 1;
    } else {
      l = mid + 1;
    }
  }
  printf("%d\n", ans);
  return 0;
}
/*
3 1 0
10000
20000
30000
*/
/*
12 1 1
1
2
3
4
5
6
7
8
21
22
23
24
*/
//O(n^3\log m) 暴力
/*
#include <algorithm>
#include <cstdio>
#include <ctype.h>
#include <cstring>
#define ll long long
const int kMaxn = 400 + 5;
const int kInf = 1e9 + 10; 
//=============================================================
int n, r, g, a[5 * kMaxn];
bool f[5 * kMaxn][kMaxn][kMaxn];
//=============================================================
inline int read() {
  int f = 1, w = 0; char ch = getchar();
  for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
  for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
  return f * w;
}
int Query(int pos_, int val_) {
  int l = 1, r = pos_, ret;
  while (l <= r) {
    int mid = (l + r) >> 1;
    if (a[mid] > val_) {
      ret = mid;
      r = mid - 1;
    } else {
      l = mid + 1;
    }
  }
  return ret;
}
void koishi() {
  int satoti;
}
bool Check(int l_) {
  memset(f, 0, sizeof (f));
  f[0][0][0] = true;
  bool ret = false;
  for (int i = 1; i <= n; ++ i) {
    int pre_red = Query(i, a[i] - l_) - 1;
    int pre_green = Query(i, a[i] - 2 * l_) - 1;
    
    int limj = std :: min(i, r), limk = std :: min(i, g);
    for (int j = 0; j <= limj; ++ j) {
      for (int k = 0; k <= limk; ++ k) {
        if (j) f[i][j][k] |= f[pre_red][j - 1][k];
        if (k) f[i][j][k] |= f[pre_green][j][k - 1];
        if (i == n) ret |= f[i][j][k];
      }
    }
  }
  return ret;
}
//=============================================================
int main() {
//  freopen("t2example.in", "r", stdin);
//  freopen("light.out", "w", stdout);
  n = read(), r = read(), g = read();
  if (r + g >= n) {
    printf("1\n");
    return 0;
  }
  for (int i = 1; i <= n; ++ i) a[i] = read();
  std :: sort(a + 1, a + n + 1);
  int l = 2, r = a[n] / (r + g), ans = a[n] / (r + g);
  while (l <= r) {
    int mid = (l + r) >> 1;
    if (Check(mid)) {
      ans = mid;
      r = mid - 1;
    } else {
      l = mid + 1;
    }
  }
  printf("%d\n", ans);
  return 0;
}
*/

正解

修改了两个边界问题的 \(O(n^2\log n \log m)\)

//
/*
By:Luckyblock
*/
#include <algorithm>
#include <cstdio>
#include <ctype.h>
#include <cstring>
#define ll long long
const int kMaxn = 2000 + 10;
const int kInf = 1e9 + 10; 
//=============================================================
int n, r, g, a[kMaxn];
int f[kMaxn][kMaxn];
//=============================================================
inline int read() {
  int f = 1, w = 0; char ch = getchar();
  for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
  for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
  return f * w;
}
void GetMax(int &fir, int sec) {
  if (sec > fir) fir = sec;
}
int Query(int pos_, int val_) {
  int l = pos_ + 1, r = n, ret;
  while (l <= r) {
    int mid = (l + r) >> 1;
    if (a[mid] - a[pos_ + 1] + 1 <= val_) { //区间长度为 a[mid] - a[pos_ + 1] + 1
      ret = mid;
      l = mid + 1;
    } else {
      r = mid - 1;
    }
  }
  return ret;
}
void koishi() {
  int satoti;
}
bool Check(int l_) {
  bool ret = false;
  memset(f, 0, sizeof (f));
  //f[0][0] 初值为 0.
  for (int i = 0; i <= r; ++ i) {
    for (int j = 0; j <= g; ++ j) {
      if (i) GetMax(f[i][j], Query(f[i - 1][j], l_));
      if (j) GetMax(f[i][j], Query(f[i][j - 1], 2 * l_));
      if(f[i][j] >= n) ret = true;
    }
  }
  return ret;
}
//=============================================================
int main() {
  // freopen("light.in", "r", stdin);
  // freopen("light.out", "w", stdout);
  n = read(), r = read(), g = read();
  if (r + g >= n) {
    printf("1\n");
    return 0;
  }
  for (int i = 1; i <= n; ++ i) a[i] = read();
  std :: sort(a + 1, a + n + 1);
  int l = 2; 
  int r = a[n];
  int ans = a[n];
  while (l <= r) {
    int mid = (l + r) >> 1;
    if (Check(mid)) {
      ans = mid;
      r = mid - 1;
    } else {
      l = mid + 1;
    }
  }
  printf("%d\n", ans);
  return 0;
}

官方 \(O(n^2 \log m)\) 做法

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int n, p, q, a[2001], l = 1, r = 0, ans = 0;
int dp[2001][2001], P[2001], Q[2001];

bool check(int L)
{
	memset(dp, 0, sizeof(dp));
	memset(P, 0, sizeof(P));
	memset(Q, 0, sizeof(Q));
	for (int i = 1; i <= n; i++)
	    for (int j = i; j <= n; j++)
	    {
	    	if (a[j] - a[i] + 1<= L) P[i] = j;
	    	if (a[j] - a[i] + 1<= 2*L) Q[i] = j;
	    }
	P[n+1] = Q[n+1] = n;
	for (int i = 0; i <= p; i++)
	    for (int j = 0; j <= q; j++)
	    {
	    	if (i > 0) dp[i][j] = max(dp[i][j], P[dp[i-1][j] + 1]);
	    	if (j > 0) dp[i][j] = max(dp[i][j], Q[dp[i][j-1] + 1]);
	    }
	return dp[p][q] == n;
}

int main()
{
	freopen("t2example.in", "r", stdin);
	freopen("t2example.out", "w", stdout);
	scanf("%d%d%d", &n, &p, &q);
	for (int i = 1; i <= n; i++)
	    scanf("%d", &a[i]);
	sort(a + 1, a + 1 + n);
	a[0] = 0;
	r = a[n] - a[1] + 1;
	if (p + q >= n) { printf("1\n"); return 0; }
	while (l <= r)
	{
		int mid = (l+r) / 2;
		if (check(mid)) ans = mid, r = mid -1; else l = mid + 1;
	}
	printf("%d\n", ans);
	return 0;
}


T3:

考场代码

//
/*
By:Luckyblock
*/
#include <algorithm>
#include <cstdio>
#include <ctype.h>
#include <queue>
#include <cstring>
#define ll long long
const int kMaxn = 5010;
const int kMaxm = 2e5 + 10;
//=============================================================
int n, m, edge_num, head[kMaxn], v[kMaxm << 1], w[kMaxm << 1], ne[kMaxm << 1];
int dis[kMaxn], secdis[kMaxn];
bool vis[kMaxn];
//=============================================================
inline int read() {
  int f = 1, w = 0; char ch = getchar();
  for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
  for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
  return f * w;
}
void AddEdge(int u_, int v_, int w_) {
  v[++ edge_num] = v_, w[edge_num] = w_;
  ne[edge_num] = head[u_], head[u_] = edge_num;
}
void Spfa() {
  std :: priority_queue <int> q;
  memset(dis, 63, sizeof (dis));
  memset(secdis, 63, sizeof (secdis));
  dis[1] = 0;
  q.push(1);
  vis[1] = true;
  while (! q.empty()) {
    int u_ = q.top(); q.pop();
    vis[u_] = false;
    for (int i = head[u_]; i; i = ne[i]) {
      int v_ = v[i], w_ = w[i];
      if (dis[u_] + w_ < dis[v_]) {
        secdis[v_] = dis[v_];
        dis[v_] = dis[u_] + w_;
        
        if (secdis[u_] + w_ < secdis[v_]) {
          secdis[v_] = secdis[u_] + w_;
        }
        if (! vis[v_]) {
          q.push(v_);
          vis[v_] = true;
        }
      } else if (dis[u_] + w_ < secdis[v_] && dis[u_] + w_ != dis[v_]) {
        secdis[v_] = dis[u_] + w_;
        if (! vis[v_]) {
          q.push(v_);
          vis[v_] = true;
        } 
      }
    }
  }
}
//=============================================================
int main() {
  freopen("maze.in", "r", stdin);
  freopen("maze.out", "w", stdout);
  n = read(), m = read();
  for (int i = 1; i <= n; ++ i) {
    int u_ = read(), v_ = read(), w_ = read();
    AddEdge(u_, v_, w_);
    AddEdge(v_, u_, w_);
    AddEdge(u_, v_, 3 * w_);
    AddEdge(v_, u_, 3 * w_);
  }
  Spfa();
  printf("%d\n", secdis[n]);
  return 0;
}

正解

#include <iostream>
#include <cstring>
using namespace std;
struct dd
{
    int x,y,z;
};
int n,r,head[5001],tail[5001],dis[5001],s1,s2,ans=1000000000;
dd a[200001];
bool b[5001];
int read()
{
	int n = 0, f = 1;
	char c = getchar();
	for(; isdigit(c); c = getchar())
	{
		n = n * 10 + c - '0';
	}
	return n * f;
}
void qsort(int l1,int r1)
{
     if (l1>=r1) return;
     int i=l1,j=r1,t=(i+j)/2;
     dd k=a[t]; a[t]=a[i];
     while (i<j)
     {
         while (a[j].x>=k.x&&i<j) --j;
         if (i<j)
         {
             a[i]=a[j];
             ++i;
         }
         while (a[i].x<k.x&&i<j) ++i;
         if (i<j)
         {
             a[j]=a[i];
             --j;
         }
     }
     a[i]=k;
     qsort(l1,i-1); qsort(i+1,r1);
     return; 
}
void dfs(int k,int s3)
{
     if (s3>s1||s3>=ans) return;
     if (k==n&&s3>s2&&ans>s3)
     {
         ans=s3;
         return;
     }
     for (int i=head[k]; i<=tail[k]; ++i)
         dfs(a[i].y,s3+a[i].z);
     return;
}
int main()
{
  freopen("maze.in", "r", stdin);
	freopen("maze.out", "w", stdout);
   	n = read(), r = read();
   for (int i=1; i<=r; ++i)
    {
        a[2*i-1].x = read();a[2*i-1].y = read();a[2*i-1].z = read();
        a[2*i].x=a[2*i-1].y; a[2*i].y=a[2*i-1].x;
        a[2*i].z=a[2*i-1].z;
    }
    r*=2;
    qsort(1,r);
    memset(head,0,sizeof(head));
    memset(tail,0,sizeof(tail));
    head[1]=1; tail[n]=r;
    for (int i=1; i<=r; ++i)
    {
        if (i>1&&a[i].x!=a[i-1].x)
            head[a[i].x]=i;
        if (i<r&&a[i].x!=a[i+1].x)
            tail[a[i].x]=i;
    }
    for (int i=1; i<=n; ++i)
        dis[i]=1000000000;
    dis[1]=0;
    memset(b,false,sizeof(b));
    for (int i=1; i<=n; ++i)
    {
        int minn=1000000000,k=0;
        for (int j=1; j<=n; ++j)
            if (dis[j]<minn&&!b[j])
            {
                minn=dis[j]; 
                k=j;
            }
        b[k]=true;
        for (int j=head[k]; j<=tail[k]; ++j)
            if (dis[a[j].y]>dis[k]+a[j].z)
            {
                dis[a[j].y]=dis[k]+a[j].z;
                if (a[j].y==n) s1=a[j].z*2;
            }
    }
    s2=dis[n]; s1+=s2;
    dfs(1,0);
    cout << ans << "\n";
    return 0;
}
posted @ 2020-09-06 15:04  Luckyblock  阅读(194)  评论(2编辑  收藏  举报