2019.11.13 题解报告


2019.11.13 题解报告

\[嘟↘嘟↗嘟↘嘟↗嘟↗嘟↗嘟↗嘟↘嘟↗\]
\[\text{By:U.N.block}\]

答题情况:

  • 总成绩 : 160 , 排名 : 8 / 37
  • T1 : 100 T2 : 60 T3 : 0

各题目分析:

  • 题目 1 :
    预估成绩 : 100 实际成绩 : 100 考试用时 : 9 : 02 ~ 9 : 51

    依旧 花费了1个小时的时间 考虑各题目 , 找到了优美的性质 ,
    写的时候思路非常清晰 , 写了四重暴力枚举 , 很快实现 , 过掉大样例 .

  • 题目 2 :
    预估成绩 : 60 实际成绩 : 60 考试用时 : 9 : 55 ~ 10 : 34

    先考虑 60分的暴力 , 很快实现 , 过了大样例 .

  • 题目 3 :
    预估成绩 : 20 实际成绩 : 0 考试用时 : 10 : 36 ~ 10 : 58

    没有什么感觉 , 写了 20 分的部分分 , 没有时间检查 , 暴力写挂了 .

    • 教训 : 要合理安排做题时间 , 在保证暴力不写挂的同时 尽量多写
      一定要留足时间用来检查

题目解析:

T1 :

可以发现 , 对于圆周上的点 , 任意选出 6 个 ,
将它们之间连线 ,有 6 种方案
6种方案中 只有一种 可以组成一个三角形

显然 , 答案即为 C(n , 6)


T2 :

60 % 数据 :

使用 01 背包 维护每一个数值 必须使用的 货币面值的集合
使用数组进行状压 , 数组中每一个数 状压25个位置的 存在情况

转移时 枚举数值 , 并使用当前枚举到的 货币面值 进行更新
状态转移方程 :
need[j][k] &= (need[j - a[i]][k] | (k == pos1 ? 1 << pos2 : 0));

最后输出 组成要求数值的必须货币面值即可
复杂度O(x * n)

100 % 数据 :

设 f[i] 表示 , 使用给定货币 , 组成数值 i 的方案数
使用01背包 , 处理出 1 ~ x 的f[i]的值

之后枚举每一种面值的货币 j,
递归检查 , 不断将 x 减去 w[j] , 判断 f[x] 与 f[x - w[j]] , f[x - w[j]] 与 f[x - 2 * w[j]] .... 是否相等
如果找到一个x , 满足 x > 0, 且使 f[x - w[j]] = 0 , 则组成x必须使用 货币j , 开始回溯
从而判断是否可以删去 该面值的货币


T3 :

题目要求 :
给定一有向图 , 边有边权 , 边权可为负数.
可使所有边同加 / 减一个数
求1->N的一条最短路 , 使其非负且最小

20 %数据 : 每个点 最多只有一条出边
则1 -> N 之间的最短路 唯一
从1点开始 dfs, 记录经过的边的数量 与 经过的边权和
根据 经过边的数量 , 将边权和 转化为 非负数即为答案

100 % 数据 :

由于边权范围较小 , 则可考虑 二分枚举 边权修改的量 , 然后检查是否合法
显然 , 若1->N的最短路 , 使其非负且最小 ,
则 1 -> 的最短路上 必然没有负环 , 且边权之和为正

显然 , 不能到达n的点 是没有贡献的 ,
则可通过从1开始 进行dfs , 对能够到达n的点 进行标记
将不能到达n的点删除 , 以重建原图

枚举答案后 , 使用dfs/bfs 优化的spfa 判断图中是否存在负环.
若存在负环 , 则枚举量不合法.
若1 -> N边权之和为负数 , 也不合法


代码实现:

T1 :

  • 考场代码 (正解):
//
/*
By:Luckyblock
*/
#include <cstdio>
#include <ctype.h>
#define ll long long
//=============================================================
ll N, ans;
//=============================================================
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 main()
{
    freopen("triangle.in", "r", stdin);
    freopen("triangle.out", "w", stdout);
    N = (ll) read();
    if(N <= 5) {putchar('0'); return 0;}
    for(int l = 6; l <= N; l ++)
      for(int u1 = 1, v1 = 4; v1 <= l - 2; v1 ++)
        for(int u2 = 3; u2 < v1; u2 ++)
          for(int v2 = v1 + 2; v2 <= l; v2 ++)
            ans += (u2 - u1 - 1) * (v2 - v1 - 1);
    printf("%I64d", ans);
}

T2:

  • 考场代码:
#include <cstdio>
#include <algorithm>
#include <ctype.h>
#define ll long long
const int MARX = 1e5 + 10;
//=============================================================
int N, X, a[MARX], need[MARX][10]; 
int ans[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 main()
{
    freopen("coin.in", "r", stdin);
    freopen("coin.out", "w", stdout);
    N = read(), X = read();
    for(int i = 1; i <= N; i ++) a[i] = read();
    
    for(int i = 1; i <= X; i ++)
      for(int j = 1; j <= 8; j ++)
        need[i][j] = (1 << 30) - 1;
    std :: sort(a + 1, a + N + 1);
    
    for(int i = 1; i <= N; i ++)
      for(int j = X; j >= a[i]; j --)
      {
        int pos1 = ((i  - 1)/ 25) + 1, pos2 = i - 25 * (pos1 - 1);
        for(int k = 1; k <= 8; k ++) 
          need[j][k] &= (need[j - a[i]][k] | (k == pos1 ? 1 << pos2 : 0));
      }
    
    for(int i = 1; i <= 8; i ++)
      for(int j = 1; j <= 25; j ++)
        if((1 << j) & need[X][i]) 
          ans[0] ++, ans[ans[0]] = a[25 * (i - 1) + j];
    
    printf("%d\n", ans[0]);
    for(int i = 1; i <= ans[0]; i ++) printf("%d ", ans[i]);
}
  • 正解 :
#include <cstdio>
#include <cctype>
#include <map>

const int MAXN = 100010;
int f[MAXN] = {1}, coin[MAXN], cnt, Max;
bool mark[MAXN], bucket[MAXN];

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 * 10 + ch - '0';
    return s * w;
}
inline int max(int a, int b) { return a > b ? a : b; }
int num(int x, int y) { return x < 0 ? 0 : f[x] - num(x - y, y); }

int main() {
//  freopen("coin.in", "r", stdin), freopen("coin.out", "w", stdout);
    int n = read(), x = read();
    for (int i = 1; i <= n; i ++) coin[i] = read(), Max = max(Max, coin[i]);
    for (int i = 1; i <= n; i ++)
      for (int j = x; j >= coin[i]; j --) 
        f[j] += f[j - coin[i]];
    for (int i = 1; i <= n; i ++) 
      if (f[x] - num(x - coin[i], coin[i]) == 0) 
        if (! bucket[coin[i]]) bucket[coin[i]] = 1, cnt ++;
    printf("%d\n", cnt);
    for (int i = 1; i <= Max; i ++) if (bucket[i]) printf("%d ", i);
    return 0;
}
/*
5 18
10 2 3 5 1
*/

T3:

  • 考场代码:
//
/*
By:Luckyblock
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <ctype.h>
#include <queue>
#define min std::min
#define max std::max
#define ll long long
const int MARX1 = 110;
const int MARX2 = 1e5 + 10;
const int INF = 1e5 + 10;
//=============================================================
struct edge
{
    int v, w, ne;
}e[MARX2 << 1];
int num, T, N, M, into[MARX1], head[MARX1];
int ans, maxt, mint;
bool flaginto1, vis[MARX1];
//=============================================================
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 add(int u, int v, int w)
{
    e[++ num].v = v, e[num].w = w;
    e[num].ne = head[u], head[u] = num;
}
void New_begin()
{
    ans = INF, num = 0, maxt = - INF, mint = INF, flaginto1 = 1;
    memset(into, 0, sizeof(into));
    memset(head, 0, sizeof(head));
    
    N = read(), M = read();
    for(int i = 1; i <= M; i ++)
    {
      int u = read(), v = read(), w = read();
      maxt = max(maxt, w), mint = min(mint, w);
      if((++ into[v]) > 1) flaginto1 = 0; 
      add(u, v ,w); 
    }
}
void solveinto1()
{
    int tot = 0, sum = 0;
    for(int u = 1; u != N; u = e[head[u]].v)
    {
      sum += e[head[u]].w, tot ++;
      if(! head[u]) {printf("-1"); return ;}    
    }
    while(sum < 0) sum += tot;
    printf("%d", sum);
}
void dfs(int u, int sum, int tot)
{
    if(u == N) 
    {
      if(sum < 0)
      {
        int tmp1 = - sum, tmp2 = tmp1 / tot;
        sum += tmp2 * tot;
        if(sum < 0) sum += tot; 
      }
      ans = min(ans, sum);
      return;
    }
    for(int i = head[u]; i; i = e[i].ne)
      if(! vis[e[i].v])
      {
        vis[e[i].v] = 1;
        dfs(e[i].v, sum + e[i].w, tot + 1);
        vis[e[i].v] = 0;
      }
}
//=============================================================
int main()
{
    freopen("home.in", "r", stdin);
    freopen("home.out", "w", stdout);
    T = read();
    while(T --)
    {
      New_begin();
      if(flaginto1) {solveinto1(); continue;}
      dfs(1, 0, 0);
      printf("%d", ans < INF ? ans : - 1);
    }
}
  • 正解 :
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<queue>
#define pa pair<int,int>
#define inf 1000000000
using namespace std;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int T,n,m,cnt,ans,mid;
int last[105],q[105],d[105];
bool mark[105],con[105];
struct data{int to,next,v;}e[200005];
void insert(int u,int v,int w)
{
    e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;e[cnt].v=w;
}
bool dfs(int x)
{
    mark[x]=1;
    for(int i=last[x];i;i=e[i].next)
        if(d[x]+e[i].v+mid<d[e[i].to]&&con[e[i].to])
        {
            if(mark[e[i].to])return 1;
            d[e[i].to]=d[x]+e[i].v+mid;
            if(dfs(e[i].to))return 1;
        }
    mark[x]=0;
    return 0;
}
void spfa()
{
    for(int i=1;i<=n;i++)d[i]=inf;
    int head=0,tail=1;
    q[0]=1;mark[1]=1;d[1]=0;
    while(head!=tail)
    {
        int now=q[head];head++;if(head==100)head=0;
        for(int i=last[now];i;i=e[i].next)
            if(d[now]+e[i].v+mid<d[e[i].to]&&con[e[i].to])
            {
                d[e[i].to]=d[now]+e[i].v+mid;
                if(!mark[e[i].to])
                {
                    mark[e[i].to]=1;
                    q[tail]=e[i].to;tail++;
                    if(tail==100)tail=0;
                }
            }
        mark[now]=0;
    }
}
void dfscon(int x)
{
    mark[x]=1;
    for(int i=last[x];i;i=e[i].next)
        if(!mark[e[i].to])
            dfscon(e[i].to);
}
bool jud()
{
    for(int i=1;i<=n;i++)
        if(con[i])
        {
            for(int j=1;j<=n;j++)d[j]=inf;
            memset(mark,0,sizeof(mark));
            if(dfs(i))return 0;
        }
    spfa();
    if(d[n]>=0&&d[n]!=inf)return 1;
    return 0;
}
int main()
{
    freopen("home.in","r",stdin);
    freopen("home.out","w",stdout);
    T=read();
    while(T--)
    {
        memset(con,1,sizeof(con));
        memset(last,0,sizeof(last));
        cnt=0;ans=-1;
        n=read();m=read();
        for(int i=1;i<=m;i++)
        {
            int u=read(),v=read(),w=read();
            insert(u,v,w);
        }
        memset(mark,0,sizeof(mark));
        dfscon(1);
        for(int i=1;i<=n;i++)if(!mark[i])con[i]=0;
        for(int i=1;i<=n;i++)
            if(con[i])
            {
                memset(mark,0,sizeof(mark));
                dfscon(i);
                if(!mark[n])con[i]=0;
            }
        int l=-100000,r=100000;
        while(l<=r)
        {
            mid=(l+r)>>1;
            if(jud())ans=d[n],r=mid-1;
            else l=mid+1;
        }
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/luckyblock/p/11852359.html