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;
}