P2662 牛场围栏

题目背景

小L通过泥萌的帮助,成功解决了二叉树的修改问题,并因此写了一篇论文,

成功报送了叉院(羡慕不?)。勤奋又勤思的他在研究生时期成功转系,考入了北京大学光华管理学院!毕业后,凭着自己积累下的浓厚经济学与计算机学的基础,成功建设了一个现代化奶牛场!

题目描述

奶牛们十分聪明,于是在牛场建围栏时打算和小L斗智斗勇!小L有N种可以建造围栏的木料,长度分别是l1,l2 … lN,每种长度的木料无限。

修建时,他将把所有选中的木料拼接在一起,因此围栏的长度就是他使用的木料长度之和。但是聪明的小L很快发现很多长度都是不能由这些木料长度相加得到的,于是决定在必要的时候把这些木料砍掉一部分以后再使用。

不过由于小L比较节约,他给自己规定:任何一根木料最多只能削短M米。当然,每根木料削去的木料长度不需要都一样。不过由于测量工具太原始,小L只能准确的削去整数米的木料,因此,如果他有两种长度分别是7和11的木料,每根最多只能砍掉1米,那么实际上就有4种可以使用的木料长度,分别是6, 7,10, 11。

因为小L相信自己的奶牛举世无双,于是让他们自己设计围栏。奶牛们不愿意自己和同伴在游戏时受到围栏的限制,于是想刁难一下小L,希望小L的木料无论经过怎样的加工,长度之和都不可能得到他们设计的围栏总长度。不过小L知道,如果围栏的长度太小,小L很快就能发现它是不能修建好的。因此她希望得到你的帮助,找出无法修建的最大围栏长度。

这一定难不倒聪明的你吧!如果你能帮小L解决这个问题,也许他会把最后的资产分给你1/8哦!

输入输出格式

输入格式:

输入的第一行包含两个整数N,  M,分别表示木料的种类和每根木料削去的最大值。以下各行每行一个整数li(1< li< 3000),表示第i根木料的原始长度。

输出格式:

输出仅一行,包含一个整数,表示不能修建的最大围栏长度。如果任何长度的围栏都可以修建或者这个最大值不存在,输出-1。

输入输出样例

输入样例#1:
复制

2 1
7 11
输出样例#1:
复制

15

说明

40 % :1< N< 10,  0< M< 300

100 % :1< N< 100,  0< M< 3000

CaptainSlow的题解

规模较小,直接上可行解DP(有个叫_DYT大佬搞了一波分析证明这个解若存在是小于\(9 \times 10^6\)) 当然我们要考虑更好的解法,如果是初中我也会写可行解DP,当然考场上实在写不出来我还是应该打个暴力骗骗满分的。

PART 1 无解?

问题确实可能无解,分两种情况:

  1. 存在数字1

    如果有1这个数字,那么所有的数字都可以被表示出来,就不存在不能表示出的数了

  2. 所有数的gcd大于1

    设这些数为\(A_1, A_2,...,A_n\),设\(q=gcd(A_1, A_2,...,A_n)\),则\(q|A_1x_1+A_2x_2+...+A_nx_n\)(\(x_1,x_2,...,x_n \in Z\))。这是一个很显然的结论,学习整除的时候是必回讲到的。所以,由于\(q > 1\),必然存在不能表示出来的数,即\(\forall q \nmid m\),都是不符合条件的数,显然这个\(m\)是可以到无穷大的。

    这两者情况我们可以先特判出来,而剩下的就是\(q=1\)的情况了,这样的话是肯定存在最大的不能表示出来的数的。 这个很显然。

PART 2 寻找

我们如何去寻找这个最大的不能被表示出来的数呢? 我们考虑所有可以被表示出来的数构成的数集\(S\),由最小数原理可知,\(S\)中一定存在最小的\(s_0\)。考虑模\(s_0\)的每一个剩余系,记为\(K_i=\lbrace x|x \equiv i\pmod{s_0}\rbrace,i=0,1,2,...,s_0-1\)。 显然\(s_0=min(A_i)\)。对\(\forall K_i\),由最小数原理,存在最小的能被表示出来的\(t_i\),\(t_i=s_0*p+i\),显然\(p>0\),否则与\(s_0\)的最小性矛盾。那么对每一个\(K_i\),最大不能被表示出来的数就是\(s_0*(p-1)+i\)。这样,问题就转化为了求每一个这样的\(t_i\),这时候,我们就引入这个被称为剩余系最短路的算法了。我们可以把每个剩余系\(K_i\)抽象为图中的点,那么连接它们的边就是\(A_i\)中的那些数。然后就用普通的最短路更新方式就可以了。我选择了用Dijkstra算法。

#include <cstdio>
#include <cstring>
#include <algorithm>
const int ARSIZE = 4005;
const int INF = 0x7f7f7f7f; int N, M, L[ARSIZE], tot_l = 0, Q[ARSIZE];
bool exist[ARSIZE] = {0}, used[ARSIZE] = {0}; inline int gcd(int a, int b) {
for (a < b ? std::swap(a, b) : (void)0; b; std::swap(a, b)) a %= b;
return a;
}
int dijkstra(); int main() {
scanf("%d%d", &N, &M);
int j, li, gd = 0;
for (int i = 0; i < N; i++) {
scanf("%d", &li);
gd = gcd(gd, li);
for (j = 0; j <= M && j < li; j++) exist[li - j] = true, gd = gcd(li - j, gd); // 很多人WA,半天查不出错,很可能就是只算了所有L[i]的gcd
}
if (exist[1] || gd > 1) puts("-1");
else printf("%d\n", dijkstra());
return 0;
} int dijkstra() {
memset(Q, 0x7f, sizeof(Q));
int i, v, k;
for (Q[0] = 0, i = 2; i <= 3000; i++) // 初始化
if (exist[i]) L[tot_l++] = i;
int MOD = L[0];
while (true) {
for (i = 0, k = -1; i < MOD; i++)
if (!used[i] && (k == -1 || Q[i] < Q[k])) k = i;
if (k == -1) break;
used[k] = true;
for (i = 1; i < tot_l; i++)
if (!used[v = (k + L[i]) % MOD]) Q[v] = std::min(Q[v], Q[k] + L[i]); // 更新其他剩余系
}
int res = -1;
for (i = 1; i < MOD; i++) res = std::max(res, Q[i] - MOD);
return res;
}

数学题(num)

题目描述

老师给小C 布置了一道数学题作为家庭作业:

给定一个数k,写出k 的倍数中各位之和最小为多少?

小C 不会做,希望你能帮帮他。

输入描述

一行一个正整数k。

输出描述

一行一个正整数,表示答案。

输入样例& 输出样例

num1.in

6

num1.out

3

num2.in

41

num2.out

5

样例说明

  1. 当k = 6 时,6 * 2 = 12,1 + 2 = 3,可以证明最小答案为3。
  2. 当k = 41 时,41 * 271 = 11111,1 + 1 + 1 + 1 + 1 = 5,可以证明最小答案为5。

数据范围

测试点编号 k
1-6 $ \leq 20$
7-20 \(\leq 10^5\)

刘老爷算法

考虑建立模n意义下的n个点,用追加数字的方式建边,由于是枚举n的倍数,所以到0点的最短路即为答案。

起点为1-9,建边边权,0-9连向摸意义下的多一位的点。

时间复杂度\(O(10 n \log n)\),注意n=1时要特判掉,不然根本就没建图,跑出来答案为INF。

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<algorithm>
#include<string>
template<class T>T read(T&x)
{
T data=0;
int w=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
w=-1;
ch=getchar();
}
while(isdigit(ch))
{
data=data*10+ch-'0';
ch=getchar();
}
return x=data*w;
}
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int INF=0x3f3f3f3f; const int MAXN=1e5+7;
int n;
struct edge
{
int nx,to,w;
}e[MAXN*10];
int head[MAXN],ecnt; void addedge(int x,int y,int w)
{
e[++ecnt].to=y,e[ecnt].w=w;
e[ecnt].nx=head[x],head[x]=ecnt;
} priority_queue <pii> H;
bool vis[MAXN];
int dis[MAXN]; int main()
{
freopen("num.in","r",stdin);
freopen("num.out","w",stdout);
read(n);
if(n==1) // edit 1
{
puts("1");
return 0;
}
for(int i=1;i<n;++i)
for(int j=0;j<10;++j)
addedge(i,(i*10+j)%n,j);
fill(dis,dis+n,INF);
for(int i=1;i<=9;++i)
{
dis[i]=i;
H.push(pii(-dis[i],i));
}
while(H.size())
{
int x=H.top().second;
H.pop();
if(vis[x])
continue;
vis[x]=1;
for(int i=head[x];i;i=e[i].nx)
{
int y=e[i].to,w=e[i].w;
if(dis[y]>dis[x]+w)
{
dis[y]=dis[x]+w;
H.push(pii(-dis[y],y));
}
}
}
printf("%d\n",dis[0]);
return 0;
}

标解

LG2662 牛场围栏 和 test20181107 数学题的更多相关文章

  1. luoguP3951 小凯的疑惑/P2662 牛场围栏

    其实就是当年sxy给我讲的墨墨的等式,只是当时比较菜听得似懂非懂. 小凯的疑惑 去年noipday1t1,当时随便猜了个结论结果猜对了,现在瞎证一下,答案是a*b-a-b. 设a为a,b中较小的一个, ...

  2. 【同余最短路】洛谷 P2662 牛场围栏

    关于同余最短路的部分 [同余最短路]P3403跳楼机/P2371墨墨的等式 [P2662牛场围栏] 题目背景 小L通过泥萌的帮助,成功解决了二叉树的修改问题,并因此写了一篇论文, 成功报送了叉院(羡慕 ...

  3. Luogu2662 牛场围栏(最短路)

    小凯的疑惑升级版的升级版.答案若存在不会超过30002-3000,暴力dp似乎勉强可以过.当然这不优美. 注意到如果能拼出长度为l的围栏,就一定能拼出长度为l+kx的围栏,其中x为最短的(或任意一个) ...

  4. 牛场围栏(vijos 1054)

    题目大意: 给出N种木棍(每种木棍数量无限)的长度(<=3000),每根木棍可以把它切掉[1,M]的长度来得到新的木棍. 求最大的不能被组合出来的长度. 如果任何长度都能组合出来或者最大值没有上 ...

  5. luogu P2662 牛场围栏

    传送门 因为一个木板可以切掉最多\(m\),所以可以先预处理哪些长度的木板可用,开个桶,然后对\([l-m,l]\)打标记,再把打了标记的数取出来 假设可用长度\(a_1,a_2,,,a_n\)从小到 ...

  6. 洛谷 P2662 牛场围栏

    做法是这样的: 首先暴力把所有可能的边长搞出来..(当然<=0的不要) 排序边长+去重, 当且仅当可行边长里面有1时,任何长度都能取到,输出-1 当且仅当所有可行边长的gcd大于1时,不能取到的 ...

  7. vijos 1054 牛场围栏 【想法题】

    这题刚看完后第一个想到的方法是背包 但仔细分析数据范围后会发现这题用背包做复杂度很高 比如对于这样的数据 2 100 2999 2898 (如果有神犇可以用背包过掉这样的数据 请回复下背包的做法) - ...

  8. P1578 奶牛浴场

    P1578 奶牛浴场 题目描述 由于John建造了牛场围栏,激起了奶牛的愤怒,奶牛的产奶量急剧减少.为了讨好奶牛,John决定在牛场中建造一个大型浴场.但是John的奶牛有一个奇怪的习惯,每头奶牛都必 ...

  9. 洛谷1578:[WC2002]奶牛浴场——题解

    https://www.luogu.org/problemnew/show/P1578#sub 由于John建造了牛场围栏,激起了奶牛的愤怒,奶牛的产奶量急剧减少.为了讨好奶牛,John决定在牛场中建 ...

随机推荐

  1. mybatis 一对一 一对多 多对多

    一对一 一对多 多对多

  2. LeetCode 8. 字符串转换整数 (atoi)(String to Integer (atoi))

    8. 字符串转换整数 (atoi) 8. String to Integer (atoi) 题目描述 LeetCode LeetCode8. String to Integer (atoi)中等 Ja ...

  3. LeetCode 22. 括号生成(Generate Parentheses)

    22. 括号生成 22. Generate Parentheses 题目描述 给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合. 例如,给出 n = 3,生成结 ...

  4. javascript——常用事件总结

      Event对象:Event 对象代表事件的状态,比如事件在其中发生的元素.键盘按键的状态.鼠标的位置.鼠标按钮的状态. 事件标签属性 当以下情况发生时,出现此事件 onabort 图像加载被中断 ...

  5. 18.Python略有小成(collections模块,re模块)

    Python(collections模块,re模块) 一.collections模块 在内置数据类型(dict.list.set.tuple)的基础上,collections模块还提供了几个额外的数据 ...

  6. gdb调试常用功能

    一.gdb中宏定义 macro define list_entry(ptr, type, member) ((type)( (char)ptr - (unsigned long)(&((typ ...

  7. Linux 环境安装 Node、nginx、docker、vsftpd、gitlab

    Linux 环境安装 centos7 # 更新yum yum update -y 0. 防火墙 firewalld 新入的JD云服务器,发现防火墙默认是关闭的. # 查看防火墙状态 systemctl ...

  8. 【LEETCODE】46、999. Available Captures for Rook

    package y2019.Algorithm.array; /** * @ProjectName: cutter-point * @Package: y2019.Algorithm.array * ...

  9. 全栈项目|小书架|服务器开发-NodeJS 使用 JWT 实现登录认证

    通过这篇 全栈项目|小书架|服务器开发-JWT 详解 文章我们对JWT有了深入的了解,那么接下来介绍JWT如何在项目中使用. 安装 $ npm install jsonwebtoken 生成 Toke ...

  10. JavaNetty

    Netty的简单使用: import io.netty.bootstrap.Bootstrap; import io.netty.buffer.Unpooled; import io.netty.ch ...