USACO 2018 Feb 题解
USACO 2018 Feb Solution
- USACO 2018 Feb Solution
- 更好的阅读体验戳此进入
- 题面 Luogu 链接
- LG-P4266 [USACO18FEB]Rest Stops S
- LG-P4264 [USACO18FEB]Teleportation S
- LG-P4088 [USACO18FEB]Slingshot P
- LG-P4265 [USACO18FEB]Snow Boots S
- LG-P4269 [USACO18FEB]Snow Boots G
- LG-P4268 [USACO18FEB]Directory Traversal G
- LG-P4267 [USACO18FEB]Taming the Herd G
- LG-P4270 [USACO18FEB]Cow Gymnasts P
- LG-P4271 [USACO18FEB]New Barns P
- UPD
更好的阅读体验戳此进入
题面 Luogu 链接
LG-P4266 [USACO18FEB]Rest Stops S
题面
这题你们基本都读完就能切吧。。真的很水。。
sssmzy 和他的私人教练 zpair 正在徒步攀爬彩虹糖山,我们将其抽象成一条长度为
Examples
Input_1
10 2 4 3 7 2 8 1
Output_1
15
Solution
没啥可说的吧?按照 long long
,这个贪心我感觉没有绿色的难度。。
Code
#define _USE_MATH_DEFINES
#include <bits/extc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
using namespace __gnu_pbds;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
template< typename T = int >
inline T read(void);
int L, N;
vector < pair < int, int >/*price, position*/ > rest;
int spdF, spdB;
int d;
ll ans(0);
int main(){
L = read(), N = read(), spdF = read(), spdB = read(); d = spdF - spdB;
for(int i = 1; i <= N; ++i){int p = read(), c = read(); rest.emplace_back(c, p);}
int cur(0); sort(rest.begin(), rest.end(), greater < pair < int, int > >());
for(auto res : rest)
ans += (ll)res.first * max(0, res.second - cur) * d, cur = max(cur, res.second);
printf("%lld\n", ans);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
short flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
LG-P4264 [USACO18FEB]Teleportation S
题面
数轴上存在
Examples
Input_1
3 -5 -7 -3 10 -2 7
Output_1
10
Solution
这道题告诉我们,题做不出来的时候要多去去厕所,去溜达一圈之后或许就突然想明白了。。
我感觉还算是一道挺有意思的题,比较奇妙,难度适中,蓝色评的也很合理。
显然当
此时显然如果有
观察发现剩下的可能性就只有
此时的原式为
然后在
剩下的两个区间也同理推导一下即可:
现在我们也就能确定下来每一条
此时我们就需要考虑一下求
不难想到 map
存即可,排序也省了。
至此,我们就做完了这道奇怪的大分类讨论,复杂度
Code
#define _USE_MATH_DEFINES
#include <bits/extc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
using namespace __gnu_pbds;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
template< typename T = int >
inline T read(void);
int N;
ll origin(0);
ll mn(LONG_LONG_MAX);
map < ll, ll > mp;
ll sum[310000]; int cnt(0);
void Insert(int p, int v){
if(mp.find(p) == mp.end())mp.insert({p, v});
else mp[p] += v;
}
void InsertAll(int sp1, int sp2, int sp3){
Insert(sp1, -1);
Insert(sp2, 2);
Insert(sp3, -1);
}
int main(){
N = read();
for(int i = 1; i <= N; ++i){
int a = read(), b = read();
origin += abs(a - b);
if(0 <= 2 * a && 2 * a < b)InsertAll(2 * a, b, 2 * b - 2 * a);
else if(b < 2 * a && 2 * a <= 0)InsertAll(2 * b - 2 * a, b, 2 * a);
else if(a < 0 && 0 < b)InsertAll(0, b, 2 * b);
else if(b < 0 && 0 < a)InsertAll(2 * b, b, 0);
}
ll cur(0), sum(origin); int lft(INT_MIN);
mn = origin;
for(auto v : mp){
sum += (ll)cur * (v.first - lft);
cur += v.second, lft = v.first;
mn = min(mn, sum);
}
printf("%lld\n", mn);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
short flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
LG-P4088 [USACO18FEB]Slingshot P
题面
数轴上存在
Examples
Input_1
2 3 0 10 1 13 8 2 1 12 5 2 20 7
Output_1
4 3 10
Solution
和上一题核心思想差不多,依然考虑,对于询问
看一下这个柿子实际上就是两个点之间的曼哈顿距离再加上一个值,说人话就是两点之间的横纵坐标差的绝对值之和再加上点
然后在具体实现的时候可以不用分类讨论写四个树状数组,直接清空原来的然后将坐标轴旋转一下,可以认为是让对应的大小关系反转,也就是把
Code
#define _USE_MATH_DEFINES
#include <bits/extc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
using namespace __gnu_pbds;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
#define NM (N + M)
template< typename T = int >
inline T read(void);
vector < int > data;
struct Node{
int idx;
int x, y;
int rx, ry;
int t;
friend const bool operator < (Node a, Node b){return a.x < b.x;}
}nod[210000];
int N, M;
ll lim;
ll ans[110000];
class BIT{
private:
ll tr[410000];
public:
void clear(void){memset(tr, 0x3f, sizeof tr);}
int lowbit(int x){return x & -x;}
void Modify(int x, ll v){while(x <= lim)tr[x] = min(tr[x], v), x += lowbit(x);}
ll Query(int x){ll ret((ll)INT_MAX * 114514); while(x)ret = min(ret, tr[x]), x -= lowbit(x); return ret;}
}bit;
void Make(void){
sort(nod + 1, nod + NM + 1);
bit.clear();
for(int i = 1; i <= NM; ++i){
if(!~nod[i].t)ans[nod[i].idx] = min(ans[nod[i].idx], bit.Query(nod[i].y) + nod[i].rx + nod[i].ry);
else bit.Modify(nod[i].y, (ll)-nod[i].rx - nod[i].ry + nod[i].t);
}
}
int main(){
memset(ans, 0x3f, sizeof ans);
N = read(), M = read();
for(int i = 1; i <= N; ++i){
int x = read(), y = read(), t = read();
nod[i] = Node{i, x, y, x, y, t};
data.emplace_back(x), data.emplace_back(y);
}
for(int i = 1; i <= M; ++i){
int x = read(), y = read();
nod[i + N] = Node{i, x, y, x, y, -1};
data.emplace_back(x), data.emplace_back(y);
ans[i] = abs(y - x);
}sort(data.begin(), data.end());
data.erase(unique(data.begin(), data.end()), data.end());
lim = data.size();
for(int i = 1; i <= NM; ++i)
nod[i].x = distance(data.begin(), lower_bound(data.begin(), data.end(), nod[i].x) + 1),
nod[i].y = distance(data.begin(), lower_bound(data.begin(), data.end(), nod[i].y) + 1);
Make();
for(int i = 1; i <= NM; ++i)
nod[i].x = -nod[i].x + lim + 1, nod[i].rx = -nod[i].rx;
Make();
for(int i = 1; i <= NM; ++i)
nod[i].y = -nod[i].y + lim + 1, nod[i].ry = -nod[i].ry;
Make();
for(int i = 1; i <= NM; ++i)
nod[i].x = -nod[i].x + lim + 1, nod[i].rx = -nod[i].rx;
Make();
for(int i = 1; i <= M; ++i)printf("%lld\n", ans[i]);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
short flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
LG-P4265 [USACO18FEB]Snow Boots S
题面
给定序列
Tips:zpair 每次走 这也是我理解错的地方)。
Examples
Input_1
10 4 0 2 8 3 6 7 5 1 4 0 2 3 4 2 3 4 7 1
Output_1
2
Solution
题目读完没啥好思路,然后一看数据范围
考虑正解,
Code
#define _USE_MATH_DEFINES
#include <bits/extc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
using namespace __gnu_pbds;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
template< typename T = int >
inline T read(void);
int N, B;
int dep[300];
int s[300], d[300];
bool dp[300][300];
// int dp[300][300];
// int pre[300][300];
int main(){
// memset(dp, 0x3f, sizeof dp);
// for(int i = 0; i <= 260; ++i)dp[i][0] = i;
dp[1][1] = 1;
N = read(), B = read();
for(int i = 1; i <= N; ++i)dep[i] = read();
for(int i = 1; i <= B; ++i)s[i] = read(), d[i] = read();
// Waiting for debugging...
// for(int i = 1; i <= B; ++i)
// for(int j = 1; j <= N; ++j)
// for(int k = j; k >= 1; --k)
// if(dep[k] <= s[i] && j - k + 1 <= d[i])pre[i][j] = k;
// else break;
// for(int i = 1; i <= B; ++i)
// for(int j = 1; j <= N; ++j)
// if(dep[j] <= s[i])
// for(int k = i - 1; k >= 0; --k)
// if(pre[i][j])dp[i][j] = min(dp[i][j], dp[k][pre[i][j] - 1] + i - k - 1);
// int mn(INT_MAX);
// for(int i = 1; i <= B; ++i)mn = min(mn, dp[i][N]);
// printf("%d\n", mn);
for(int i = 1; i <= B; ++i)
for(int j = 1; j <= N; ++j)
if(dp[i][j])
for(int k = i; k <= B; ++k)
if(s[k] >= dep[j])
for(int l = j + 1; l <= min(N, j + d[k]); ++l)
if(s[k] >= dep[l])
dp[k][l] = true;
for(int i = 1; i <= B; ++i)if(dp[i][N])printf("%d\n", i - 1), exit(0);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
short flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
LG-P4269 [USACO18FEB]Snow Boots G
题面
给定长度为
Examples
Input_1
8 7 0 3 8 5 6 9 0 0 0 5 0 6 6 2 8 1 10 1 5 3 150 7
Output_1
0 1 1 0 1 1 1
Solution
题面简化之后一个很显然的做法就是线段树,认为叶子节点符合要求的时候就是
Code
#define _USE_MATH_DEFINES
#include <bits/extc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
using namespace __gnu_pbds;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
template< typename T = int >
inline T read(void);
// struct List{
// List *pre, *nxt;
// int dep;
// };
// List* lst[110000];
struct List{
int pre, nxt;
int dep;
}lst[110000];
int N, B;
struct Snow{
int idx, dep;
friend const bool operator < (const Snow &a, const Snow &b){return a.dep > b.dep;}
}snow[110000];
struct Boot{
int idx, dis, dep;
friend const bool operator < (const Boot &a, const Boot &b){return a.dep > b.dep;}
}boot[110000];
bool ans[110000];
int main(){
N = read(), B = read();
for(int i = 1; i <= N; ++i){
// lst[i]->dep = read();
// if(i != 1)lst[i]->pre = lst[i - 1];
// if(i != N)lst[i]->nxt = lst[i + 1];
snow[i] = Snow{i, read()};
lst[i] = List{i - 1, i + 1, snow[i].dep};
}
for(int i = 1; i <= B; ++i){int s = read(), d = read(); boot[i] = Boot{i, d, s};}
sort(snow + 1, snow + N + 1), sort(boot + 1, boot + B + 1);
int cur(0), mx(0);
for(int i = 1; i <= B; ++i){
while(cur <= N - 1 && snow[cur + 1].dep > boot[i].dep){
++cur;
lst[lst[snow[cur].idx].nxt].pre = lst[snow[cur].idx].pre;
lst[lst[snow[cur].idx].pre].nxt = lst[snow[cur].idx].nxt;
mx = max(mx, lst[snow[cur].idx].nxt - lst[snow[cur].idx].pre);
}if(mx <= boot[i].dis)ans[boot[i].idx] = true;
}
for(int i = 1; i <= B; ++i)printf("%d\n", ans[i] ? 1 : 0);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
short flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
LG-P4268 [USACO18FEB]Directory Traversal G
题面
sssmzy 在他的电脑中存储了很多学习资料,我们都知道在系统大多数路径中都存在名为 ..
的路径,通过此路径可以回到上一级(通过 .
和 ..
等连接的一般叫做相对路径)。给定一些文件夹和文件之间的关系,sssmzy 可以处于某个文件夹中,他要访问所有的文件,显然这些文件相对于其所在文件夹会有很多路径,你需要最小化每个文件路径长度和,并输出。特别地,我们不考虑使用 ./
。
对于样例,其文件之间的结构为:
bessie/ --folder1/ ----file1 ----folder2/ ------file2 --folder3/ ----file3 --file4
可以证明从 folder2
出发会有最小路径长度和,路径为:
../file1 file2 ../../folder3/file3 ../../file4
关于输入格式:
第一行包含一个整数N(
接下来有
Examples
Input_1
8 bessie 3 2 6 8 folder1 2 3 4 file1 0 folder2 1 5 file2 0 folder3 1 7 file3 0 file4 0
Output_1
42
Solution
一个有点像换根 DP 但是没换根的树形 DP。
首先根据定义,显然不会有空文件夹,所以叶子节点均为文件夹。
首先以根目录的文件夹为根 dfs 一遍,记录一大堆东西,以根目录为根的路径长度和
然后再做一遍不换根的换根 DP,同样深搜,令子节点答案为
至于 ../
,不难理解吧,这样跑一遍求一下最大的
Code
#define _USE_MATH_DEFINES
#include <bits/extc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
using namespace __gnu_pbds;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
template< typename T = int >
inline T read(void);
struct Edge{
Edge* nxt;
int to;
OPNEW;
}ed[210000];
ROPNEW(ed);
Edge* head[110000];
int N;
ll f[110000];
int leaf[110000], w[110000];
ll dis[110000];
ll mn;
void dfs_pre(int p = 1, int fa = 0){
if(p != 1 && !head[p]->nxt)leaf[p] = 1, f[1] += dis[fa] + w[p];
else dis[p] = p == 1 ? 0 : dis[fa] + w[p] + 1;
for(auto i = head[p]; i; i = i->nxt)if(SON != fa)dfs_pre(SON, p), leaf[p] += leaf[SON];
}
void dfs(int p = 1, int fa = 0){
if(p != 1 && head[p]->nxt)f[p] = f[fa] - (ll)leaf[p] * (w[p] + 1) + (ll)(leaf[1] - leaf[p]) * 3, mn = min(mn, f[p]);
for(auto i = head[p]; i; i = i->nxt)if(SON != fa)dfs(SON, p);
}
int main(){
N = read();
for(int i = 1; i <= N; ++i){
string dir;
cin >> dir;
w[i] = i == 1 ? 0 : (int)dir.size();
int M = read();
for(int j = 1; j <= M; ++j){
int son = read();
head[i] = new Edge{head[i], son};
head[son] = new Edge{head[son], i};
}
}
dfs_pre();
mn = f[1];
dfs();
printf("%lld\n", mn);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
short flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
LG-P4267 [USACO18FEB]Taming the Herd G
题面
原题面说的很奇怪,我理解了半天才看懂,所以这题就不简化题面了。。
一大清早,Farmer John就被木材破裂的声音吵醒了。是这些奶牛们干的,她们又逃出牛棚了!
Farmer John已经厌烦了奶牛在清晨出逃,他觉得受够了:是时候采取强硬措施了。他在牛棚的墙上钉了一个计数器,追踪从上次出逃开始经过的天数。所以如果某一天早上发生了出逃事件,这一天的计数器就为;如果最近的出逃是 天前,计数器读数就为 。Farmer John一丝不苟地记录了每一天计数器的读数。 年末到了,Farmer John准备做一些统计。他说,你们这些奶牛会付出代价的!然而他的某些记录看上去不太对劲……
Farmer John想要知道从他开始记录以来发生过多少次出逃。但是,他怀疑这些奶牛篡改了它的记录,现在他所确定的只有他是从发生出逃的某一天开始记录的。请帮助他求出,对于每个从他开始记录以来可能发生的出逃次数,他被篡改了的记录条数的最小值。
输入格式(文件名:taming.in):
输入的第一行包含一个整数( ),表示从Farmer John开始对奶牛出逃计数器进行计数以来已经经过的天数。
第二行包含个空格分隔的整数。第 个整数是一个非负整数 (不超过 ),表示在第 天计数器的数字是 ,除非奶牛篡改了这一天的记录条目。 输出格式(文件名:taming.out):
输出包含个整数,每行一个。第 个整数为所有发生 次出逃的事件序列中,与该事件序列不一致的记录条目条数的最小值。
阳间题面:
题目说在一个牛棚里有一个计数器,用来记录每一天有没有奶牛逃跑。
假设今天是第 i 天,如果今天有奶牛逃跑,那么计数器就为 0 。
如果在第 i−j 天有奶牛逃跑,那么计数器就为 j 。
但是记录有可能被篡改,给定一个记录的数列(有可能被篡改过),求在有 i 个奶牛逃跑时的最小被篡改量。
Input_1
6 1 1 2 0 0 1
Output_1
4 2 1 2 3 4
Solution
一道比较裸的 DP,难度在于理解题意。
令
Code
#define _USE_MATH_DEFINES
#include <bits/extc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
using namespace __gnu_pbds;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
template< typename T = int >
inline T read(void);
int N;
int a[110];
int dp[110][110];
int cal(int s, int t){
int cnt(0);
for(int i = s; i <= t; ++i)if(a[i] != i - s)++cnt;
return cnt;
}
int main(){
memset(dp, 0x3f, sizeof dp);
dp[0][0] = 0;
N = read();
for(int i = 1; i <= N; ++i)a[i] = read();
for(int i = 0; i <= N; ++i)
for(int j = 1; j <= N; ++j)
for(int k = i + 1; k <= N; ++k)
dp[k][j] = min(dp[k][j], dp[i][j - 1] + cal(i + 1, k));
for(int i = 1; i <= N; ++i)printf("%d\n", dp[N][i]);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
short flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
LG-P4270 [USACO18FEB]Cow Gymnasts P
题面
存在
对于样例,有
Examples
Input_1
4
Output_1
6
Solution
一道纯粹的人类智慧题。。。
然后我们这里定义的循环周期并不是一般圆周运动绕一圈的操作次数,而是一头原来在第
首先对于符合条件的排列,有好几个奇怪的性质:
- 对于第
层的奶牛,只能是从其他平台第 层的奶牛平移过来,而不可以是从更高层的奶牛掉下来。
证明:因为是符合条件的排列,我们假设序列中最高的层数为
- 对于第
层奶牛的循环周期(定义参考伊始)是 的约数。
证明:显然某一时刻第
- 第
层奶牛循环周期是第 层奶牛循环周期的约数。
证明:考虑由性质一,第
- 任意两个平台之间的奶牛数量差不超过
。
证明:由性质二不难得出
以此我们便可以得出结论:
证明:首先枚举层数最小的平台有
此时根据我们前面的性质一定有标号相同的点值相同,那么此时
然后此时我们还要考虑,为什么仅枚举是否为
随便举几个例子可以发现这个结论似乎正确,那么我们现在尝试严谨一点地去证明,有结论,对于所有非
首先考虑如果有非
所以换一个说法理解,我们枚举的便为此处是
然后发现数据范围这个柿子肯定过不去,于是考虑优化,继续推柿子:
这个式子应该是可以继续推下去直到严格
显然我们可以通过分解质因数求欧拉函数,具体地,令
那么:
然后我们答案式子枚举的是 long long
。然后过程中是需要先让 long long
,当然像我一样直接用 __int128_t
可以直接忽略这些问题。
至此此题解决,还是很精妙的。
Code
#define _USE_MATH_DEFINES
#include <bits/extc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
using namespace __gnu_pbds;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
#define MOD (ll)(1e9 + 7)
template< typename T = int >
inline T read(void);
ll N;
int tot(0);
pair < ll, int > fact[1100000];
int cur[1100000];
__int128_t ans(0);
__int128_t qpow(ll a, ll b){
__int128_t ret(1), mul(a);
while(b){
if(b & 1)ret = ret * mul % MOD;
b >>= 1;
mul = mul * mul % MOD;
}return ret;
}
void dfs(int p = 1, ll base = 1, __int128_t phi = 1, __int128_t div = 1){
if(p > tot){
phi *= base, phi /= div, phi %= MOD;
ans = (ans + phi * qpow(2, N / base) % MOD) % MOD;
return;
}
dfs(p + 1, base, phi, div);
phi *= fact[p].first - 1;
div *= fact[p].first;
for(int i = 1; i <= fact[p].second; ++i)
base *= fact[p].first, dfs(p + 1, base, phi, div);
}
int main(){
N = read < ll >();
ll tmp(N); ll cur(2), cnt(0);
while(tmp > 1){
if(cur * cur > tmp)break;
while(tmp % cur == 0)tmp /= cur, ++cnt;
if(cnt)fact[++tot] = {cur, cnt}, cnt = 0;
++cur;
}if(tmp > 1)fact[++tot] = {tmp, 1};
dfs();
ans = ((((ans + 2 - N) % MOD) - qpow(2, N)) % MOD + MOD) % MOD;
printf("%lld\n", (ll)ans);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
short flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
LG-P4271 [USACO18FEB]New Barns P
题面
奇怪题,先咕着,laterrrrrr 再来写。
Examples
Input_1
Output_1
Solution
Code
UPD
update-2022_11_10 初稿
本文作者:tsawke
本文链接:https://www.cnblogs.com/tsawke/p/16945853.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步