USACO 2018 Feb Solution更好的阅读体验戳此进入题面 Luogu 链接LG-P4266 [USACO18FEB]Rest Stops S题面ExamplesSolutionCodeLG-P4264 [USACO18FEB]Teleportation S题面ExamplesSolutionCodeLG-P4088 [USACO18FEB]Slingshot P题面ExamplesSolutionCodeLG-P4265 [USACO18FEB]Snow Boots S题面ExamplesSolutionCodeLG-P4269 [USACO18FEB]Snow Boots G题面ExamplesSolutionCodeLG-P4268 [USACO18FEB]Directory Traversal G题面ExamplesSolutionCodeLG-P4267 [USACO18FEB]Taming the Herd G题面SolutionCodeLG-P4270 [USACO18FEB]Cow Gymnasts P题面ExamplesSolutionCodeLG-P4271 [USACO18FEB]New Barns P题面ExamplesSolutionCodeUPD
这题你们基本都读完就能切吧。。真的很水。。
sssmzy 和他的私人教练 zpair 正在徒步攀爬彩虹糖山,我们将其抽象成一条长度为
Input_1
xxxxxxxxxx
3110 2 4 3
27 2
38 1
Output_1
xxxxxxxxxx
1115
没啥可说的吧?按照 long long
,这个贪心我感觉没有绿色的难度。。
xxxxxxxxxx
571
2
3
4
5
6
7
8
9
10
11using namespace std;
12using namespace __gnu_pbds;
13
14mt19937 rnd(random_device{}());
15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
16bool rnddd(int x){return rndd(1, 100) <= x;}
17
18typedef unsigned int uint;
19typedef unsigned long long unll;
20typedef long long ll;
21typedef long double ld;
22
23template< typename T = int >
24inline T read(void);
25
26int L, N;
27vector < pair < int, int >/*price, position*/ > rest;
28int spdF, spdB;
29int d;
30ll ans(0);
31
32int main(){
33 L = read(), N = read(), spdF = read(), spdB = read(); d = spdF - spdB;
34 for(int i = 1; i <= N; ++i){int p = read(), c = read(); rest.emplace_back(c, p);}
35 int cur(0); sort(rest.begin(), rest.end(), greater < pair < int, int > >());
36 for(auto res : rest)
37 ans += (ll)res.first * max(0, res.second - cur) * d, cur = max(cur, res.second);
38 printf("%lld\n", ans);
39 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
40 return 0;
41}
42
43template < typename T >
44inline T read(void){
45 T ret(0);
46 short flag(1);
47 char c = getchar();
48 while(c != '-' && !isdigit(c))c = getchar();
49 if(c == '-')flag = -1, c = getchar();
50 while(isdigit(c)){
51 ret *= 10;
52 ret += int(c - '0');
53 c = getchar();
54 }
55 ret *= flag;
56 return ret;
57}
数轴上存在
Input_1
xxxxxxxxxx
413
2-5 -7
3-3 10
4-2 7
Output_1
xxxxxxxxxx
1110
这道题告诉我们,题做不出来的时候要多去去厕所,去溜达一圈之后或许就突然想明白了。。
我感觉还算是一道挺有意思的题,比较奇妙,难度适中,蓝色评的也很合理。
显然当
此时显然如果有
观察发现剩下的可能性就只有
此时的原式为
然后在
剩下的两个区间也同理推导一下即可:
现在我们也就能确定下来每一条
此时我们就需要考虑一下求
不难想到 map
存即可,排序也省了。
至此,我们就做完了这道奇怪的大分类讨论,复杂度
xxxxxxxxxx
781
2
3
4
5
6
7
8
9
10
11using namespace std;
12using namespace __gnu_pbds;
13
14mt19937 rnd(random_device{}());
15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
16bool rnddd(int x){return rndd(1, 100) <= x;}
17
18typedef unsigned int uint;
19typedef unsigned long long unll;
20typedef long long ll;
21typedef long double ld;
22
23template< typename T = int >
24inline T read(void);
25
26int N;
27ll origin(0);
28ll mn(LONG_LONG_MAX);
29map < ll, ll > mp;
30ll sum[310000]; int cnt(0);
31
32void Insert(int p, int v){
33 if(mp.find(p) == mp.end())mp.insert({p, v});
34 else mp[p] += v;
35}
36void InsertAll(int sp1, int sp2, int sp3){
37 Insert(sp1, -1);
38 Insert(sp2, 2);
39 Insert(sp3, -1);
40}
41
42int main(){
43 N = read();
44 for(int i = 1; i <= N; ++i){
45 int a = read(), b = read();
46 origin += abs(a - b);
47 if(0 <= 2 * a && 2 * a < b)InsertAll(2 * a, b, 2 * b - 2 * a);
48 else if(b < 2 * a && 2 * a <= 0)InsertAll(2 * b - 2 * a, b, 2 * a);
49 else if(a < 0 && 0 < b)InsertAll(0, b, 2 * b);
50 else if(b < 0 && 0 < a)InsertAll(2 * b, b, 0);
51 }
52 ll cur(0), sum(origin); int lft(INT_MIN);
53 mn = origin;
54 for(auto v : mp){
55 sum += (ll)cur * (v.first - lft);
56 cur += v.second, lft = v.first;
57 mn = min(mn, sum);
58 }
59 printf("%lld\n", mn);
60 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
61 return 0;
62}
63
64template < typename T >
65inline T read(void){
66 T ret(0);
67 short flag(1);
68 char c = getchar();
69 while(c != '-' && !isdigit(c))c = getchar();
70 if(c == '-')flag = -1, c = getchar();
71 while(isdigit(c)){
72 ret *= 10;
73 ret += int(c - '0');
74 c = getchar();
75 }
76 ret *= flag;
77 return ret;
78}
数轴上存在
Input_1
xxxxxxxxxx
612 3
20 10 1
313 8 2
41 12
55 2
620 7
Output_1
xxxxxxxxxx
314
23
310
和上一题核心思想差不多,依然考虑,对于询问
看一下这个柿子实际上就是两个点之间的曼哈顿距离再加上一个值,说人话就是两点之间的横纵坐标差的绝对值之和再加上点
然后在具体实现的时候可以不用分类讨论写四个树状数组,直接清空原来的然后将坐标轴旋转一下,可以认为是让对应的大小关系反转,也就是把
xxxxxxxxxx
1081
2
3
4
5
6
7
8
9
10
11using namespace std;
12using namespace __gnu_pbds;
13
14mt19937 rnd(random_device{}());
15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
16bool rnddd(int x){return rndd(1, 100) <= x;}
17
18typedef unsigned int uint;
19typedef unsigned long long unll;
20typedef long long ll;
21typedef long double ld;
22
23
24
25template< typename T = int >
26inline T read(void);
27
28vector < int > data;
29struct Node{
30 int idx;
31 int x, y;
32 int rx, ry;
33 int t;
34 friend const bool operator < (Node a, Node b){return a.x < b.x;}
35}nod[210000];
36
37int N, M;
38ll lim;
39ll ans[110000];
40
41class BIT{
42private:
43 ll tr[410000];
44public:
45 void clear(void){memset(tr, 0x3f, sizeof tr);}
46 int lowbit(int x){return x & -x;}
47 void Modify(int x, ll v){while(x <= lim)tr[x] = min(tr[x], v), x += lowbit(x);}
48 ll Query(int x){ll ret((ll)INT_MAX * 114514); while(x)ret = min(ret, tr[x]), x -= lowbit(x); return ret;}
49}bit;
50
51void Make(void){
52 sort(nod + 1, nod + NM + 1);
53 bit.clear();
54 for(int i = 1; i <= NM; ++i){
55 if(!~nod[i].t)ans[nod[i].idx] = min(ans[nod[i].idx], bit.Query(nod[i].y) + nod[i].rx + nod[i].ry);
56 else bit.Modify(nod[i].y, (ll)-nod[i].rx - nod[i].ry + nod[i].t);
57 }
58}
59
60int main(){
61 memset(ans, 0x3f, sizeof ans);
62 N = read(), M = read();
63 for(int i = 1; i <= N; ++i){
64 int x = read(), y = read(), t = read();
65 nod[i] = Node{i, x, y, x, y, t};
66 data.emplace_back(x), data.emplace_back(y);
67 }
68 for(int i = 1; i <= M; ++i){
69 int x = read(), y = read();
70 nod[i + N] = Node{i, x, y, x, y, -1};
71 data.emplace_back(x), data.emplace_back(y);
72 ans[i] = abs(y - x);
73 }sort(data.begin(), data.end());
74 data.erase(unique(data.begin(), data.end()), data.end());
75 lim = data.size();
76 for(int i = 1; i <= NM; ++i)
77 nod[i].x = distance(data.begin(), lower_bound(data.begin(), data.end(), nod[i].x) + 1),
78 nod[i].y = distance(data.begin(), lower_bound(data.begin(), data.end(), nod[i].y) + 1);
79 Make();
80 for(int i = 1; i <= NM; ++i)
81 nod[i].x = -nod[i].x + lim + 1, nod[i].rx = -nod[i].rx;
82 Make();
83 for(int i = 1; i <= NM; ++i)
84 nod[i].y = -nod[i].y + lim + 1, nod[i].ry = -nod[i].ry;
85 Make();
86 for(int i = 1; i <= NM; ++i)
87 nod[i].x = -nod[i].x + lim + 1, nod[i].rx = -nod[i].rx;
88 Make();
89 for(int i = 1; i <= M; ++i)printf("%lld\n", ans[i]);
90 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
91 return 0;
92}
93
94template < typename T >
95inline T read(void){
96 T ret(0);
97 short flag(1);
98 char c = getchar();
99 while(c != '-' && !isdigit(c))c = getchar();
100 if(c == '-')flag = -1, c = getchar();
101 while(isdigit(c)){
102 ret *= 10;
103 ret += int(c - '0');
104 c = getchar();
105 }
106 ret *= flag;
107 return ret;
108}
给定序列
Tips:zpair 每次走 这也是我理解错的地方)。
Input_1
xxxxxxxxxx
6110 4
20 2 8 3 6 7 5 1 4 0
32 3
44 2
53 4
67 1
Output_1
xxxxxxxxxx
112
题目读完没啥好思路,然后一看数据范围
考虑正解,
xxxxxxxxxx
831
2
3
4
5
6
7
8
9
10
11using namespace std;
12using namespace __gnu_pbds;
13
14mt19937 rnd(random_device{}());
15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
16bool rnddd(int x){return rndd(1, 100) <= x;}
17
18typedef unsigned int uint;
19typedef unsigned long long unll;
20typedef long long ll;
21typedef long double ld;
22
23template< typename T = int >
24inline T read(void);
25
26int N, B;
27int dep[300];
28int s[300], d[300];
29bool dp[300][300];
30// int dp[300][300];
31// int pre[300][300];
32
33int main(){
34 // memset(dp, 0x3f, sizeof dp);
35 // for(int i = 0; i <= 260; ++i)dp[i][0] = i;
36 dp[1][1] = 1;
37 N = read(), B = read();
38 for(int i = 1; i <= N; ++i)dep[i] = read();
39 for(int i = 1; i <= B; ++i)s[i] = read(), d[i] = read();
40
41 // Waiting for debugging...
42 // for(int i = 1; i <= B; ++i)
43 // for(int j = 1; j <= N; ++j)
44 // for(int k = j; k >= 1; --k)
45 // if(dep[k] <= s[i] && j - k + 1 <= d[i])pre[i][j] = k;
46 // else break;
47 // for(int i = 1; i <= B; ++i)
48 // for(int j = 1; j <= N; ++j)
49 // if(dep[j] <= s[i])
50 // for(int k = i - 1; k >= 0; --k)
51 // if(pre[i][j])dp[i][j] = min(dp[i][j], dp[k][pre[i][j] - 1] + i - k - 1);
52 // int mn(INT_MAX);
53 // for(int i = 1; i <= B; ++i)mn = min(mn, dp[i][N]);
54 // printf("%d\n", mn);
55
56 for(int i = 1; i <= B; ++i)
57 for(int j = 1; j <= N; ++j)
58 if(dp[i][j])
59 for(int k = i; k <= B; ++k)
60 if(s[k] >= dep[j])
61 for(int l = j + 1; l <= min(N, j + d[k]); ++l)
62 if(s[k] >= dep[l])
63 dp[k][l] = true;
64 for(int i = 1; i <= B; ++i)if(dp[i][N])printf("%d\n", i - 1), exit(0);
65 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
66 return 0;
67}
68
69template < typename T >
70inline T read(void){
71 T ret(0);
72 short flag(1);
73 char c = getchar();
74 while(c != '-' && !isdigit(c))c = getchar();
75 if(c == '-')flag = -1, c = getchar();
76 while(isdigit(c)){
77 ret *= 10;
78 ret += int(c - '0');
79 c = getchar();
80 }
81 ret *= flag;
82 return ret;
83}
给定长度为
Input_1
xxxxxxxxxx
918 7
20 3 8 5 6 9 0 0
30 5
40 6
56 2
68 1
710 1
85 3
9150 7
Output_1
xxxxxxxxxx
710
21
31
40
51
61
71
题面简化之后一个很显然的做法就是线段树,认为叶子节点符合要求的时候就是
xxxxxxxxxx
851
2
3
4
5
6
7
8
9
10
11using namespace std;
12using namespace __gnu_pbds;
13
14mt19937 rnd(random_device{}());
15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
16bool rnddd(int x){return rndd(1, 100) <= x;}
17
18typedef unsigned int uint;
19typedef unsigned long long unll;
20typedef long long ll;
21typedef long double ld;
22
23template< typename T = int >
24inline T read(void);
25
26// struct List{
27// List *pre, *nxt;
28// int dep;
29// };
30// List* lst[110000];
31struct List{
32 int pre, nxt;
33 int dep;
34}lst[110000];
35int N, B;
36struct Snow{
37 int idx, dep;
38 friend const bool operator < (const Snow &a, const Snow &b){return a.dep > b.dep;}
39}snow[110000];
40struct Boot{
41 int idx, dis, dep;
42 friend const bool operator < (const Boot &a, const Boot &b){return a.dep > b.dep;}
43}boot[110000];
44bool ans[110000];
45
46int main(){
47 N = read(), B = read();
48 for(int i = 1; i <= N; ++i){
49 // lst[i]->dep = read();
50 // if(i != 1)lst[i]->pre = lst[i - 1];
51 // if(i != N)lst[i]->nxt = lst[i + 1];
52 snow[i] = Snow{i, read()};
53 lst[i] = List{i - 1, i + 1, snow[i].dep};
54 }
55 for(int i = 1; i <= B; ++i){int s = read(), d = read(); boot[i] = Boot{i, d, s};}
56 sort(snow + 1, snow + N + 1), sort(boot + 1, boot + B + 1);
57 int cur(0), mx(0);
58 for(int i = 1; i <= B; ++i){
59 while(cur <= N - 1 && snow[cur + 1].dep > boot[i].dep){
60 ++cur;
61 lst[lst[snow[cur].idx].nxt].pre = lst[snow[cur].idx].pre;
62 lst[lst[snow[cur].idx].pre].nxt = lst[snow[cur].idx].nxt;
63 mx = max(mx, lst[snow[cur].idx].nxt - lst[snow[cur].idx].pre);
64 }if(mx <= boot[i].dis)ans[boot[i].idx] = true;
65 }
66 for(int i = 1; i <= B; ++i)printf("%d\n", ans[i] ? 1 : 0);
67 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
68 return 0;
69}
70
71template < typename T >
72inline T read(void){
73 T ret(0);
74 short flag(1);
75 char c = getchar();
76 while(c != '-' && !isdigit(c))c = getchar();
77 if(c == '-')flag = -1, c = getchar();
78 while(isdigit(c)){
79 ret *= 10;
80 ret += int(c - '0');
81 c = getchar();
82 }
83 ret *= flag;
84 return ret;
85}
sssmzy 在他的电脑中存储了很多学习资料,我们都知道在系统大多数路径中都存在名为 ..
的路径,通过此路径可以回到上一级(通过 .
和 ..
等连接的一般叫做相对路径)。给定一些文件夹和文件之间的关系,sssmzy 可以处于某个文件夹中,他要访问所有的文件,显然这些文件相对于其所在文件夹会有很多路径,你需要最小化每个文件路径长度和,并输出。特别地,我们不考虑使用 ./
。
对于样例,其文件之间的结构为:
xxxxxxxxxx
81bessie/
2--folder1/
3----file1
4----folder2/
5------file2
6--folder3/
7----file3
8--file4
可以证明从 folder2
出发会有最小路径长度和,路径为:
xxxxxxxxxx
41../file1
2file2
3../../folder3/file3
4../../file4
关于输入格式:
第一行包含一个整数N(
Input_1
xxxxxxxxxx
918
2bessie 3 2 6 8
3folder1 2 3 4
4file1 0
5folder2 1 5
6file2 0
7folder3 1 7
8file3 0
9file4 0
Output_1
xxxxxxxxxx
1142
一个有点像换根 DP 但是没换根的树形 DP。
首先根据定义,显然不会有空文件夹,所以叶子节点均为文件夹。
首先以根目录的文件夹为根 dfs 一遍,记录一大堆东西,以根目录为根的路径长度和 /
),特别地,
然后再做一遍不换根的换根 DP,同样深搜,令子节点答案为
至于 ../
,不难理解吧,这样跑一遍求一下最大的
xxxxxxxxxx
851
2
3
4
5
6
7
8
9
10
11using namespace std;
12using namespace __gnu_pbds;
13
14mt19937 rnd(random_device{}());
15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
16bool rnddd(int x){return rndd(1, 100) <= x;}
17
18typedef unsigned int uint;
19typedef unsigned long long unll;
20typedef long long ll;
21typedef long double ld;
22
23template< typename T = int >
24inline T read(void);
25
26struct Edge{
27 Edge* nxt;
28 int to;
29 OPNEW;
30}ed[210000];
31ROPNEW(ed);
32Edge* head[110000];
33
34int N;
35ll f[110000];
36int leaf[110000], w[110000];
37ll dis[110000];
38ll mn;
39
40void dfs_pre(int p = 1, int fa = 0){
41 if(p != 1 && !head[p]->nxt)leaf[p] = 1, f[1] += dis[fa] + w[p];
42 else dis[p] = p == 1 ? 0 : dis[fa] + w[p] + 1;
43 for(auto i = head[p]; i; i = i->nxt)if(SON != fa)dfs_pre(SON, p), leaf[p] += leaf[SON];
44}
45void dfs(int p = 1, int fa = 0){
46 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]);
47 for(auto i = head[p]; i; i = i->nxt)if(SON != fa)dfs(SON, p);
48}
49
50int main(){
51 N = read();
52 for(int i = 1; i <= N; ++i){
53 string dir;
54 cin >> dir;
55 w[i] = i == 1 ? 0 : (int)dir.size();
56 int M = read();
57 for(int j = 1; j <= M; ++j){
58 int son = read();
59 head[i] = new Edge{head[i], son};
60 head[son] = new Edge{head[son], i};
61 }
62 }
63 dfs_pre();
64 mn = f[1];
65 dfs();
66 printf("%lld\n", mn);
67 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
68 return 0;
69}
70
71template < typename T >
72inline T read(void){
73 T ret(0);
74 short flag(1);
75 char c = getchar();
76 while(c != '-' && !isdigit(c))c = getchar();
77 if(c == '-')flag = -1, c = getchar();
78 while(isdigit(c)){
79 ret *= 10;
80 ret += int(c - '0');
81 c = getchar();
82 }
83 ret *= flag;
84 return ret;
85}
原题面说的很奇怪,我理解了半天才看懂,所以这题就不简化题面了。。
一大清早,Farmer John就被木材破裂的声音吵醒了。是这些奶牛们干的,她们又逃出牛棚了! Farmer John已经厌烦了奶牛在清晨出逃,他觉得受够了:是时候采取强硬措施了。他在牛棚的墙上钉了一个计数器,追踪从上次出逃开始经过的天数。所以如果某一天早上发生了出逃事件,这一天的计数器就为
;如果最近的出逃是 天前,计数器读数就为 。Farmer John一丝不苟地记录了每一天计数器的读数。 年末到了,Farmer John准备做一些统计。他说,你们这些奶牛会付出代价的!然而他的某些记录看上去不太对劲……
Farmer John想要知道从他开始记录以来发生过多少次出逃。但是,他怀疑这些奶牛篡改了它的记录,现在他所确定的只有他是从发生出逃的某一天开始记录的。请帮助他求出,对于每个从他开始记录以来可能发生的出逃次数,他被篡改了的记录条数的最小值。
输入格式(文件名:taming.in): 输入的第一行包含一个整数
( ),表示从Farmer John开始对奶牛出逃计数器进行计数以来已经经过的天数。 第二行包含 个空格分隔的整数。第 个整数是一个非负整数 (不超过 ),表示在第 天计数器的数字是 ,除非奶牛篡改了这一天的记录条目。 输出格式(文件名:taming.out): 输出包含
个整数,每行一个。第 个整数为所有发生 次出逃的事件序列中,与该事件序列不一致的记录条目条数的最小值。
阳间题面:
题目说在一个牛棚里有一个计数器,用来记录每一天有没有奶牛逃跑。 假设今天是第 i 天,如果今天有奶牛逃跑,那么计数器就为 0 。 如果在第 i−j 天有奶牛逃跑,那么计数器就为 j 。 但是记录有可能被篡改,给定一个记录的数列(有可能被篡改过),求在有 i 个奶牛逃跑时的最小被篡改量。
Input_1
xxxxxxxxxx
216
21 1 2 0 0 1
Output_1
xxxxxxxxxx
614
22
31
42
53
64
一道比较裸的 DP,难度在于理解题意。
令
xxxxxxxxxx
631
2
3
4
5
6
7
8
9
10
11using namespace std;
12using namespace __gnu_pbds;
13
14mt19937 rnd(random_device{}());
15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
16bool rnddd(int x){return rndd(1, 100) <= x;}
17
18typedef unsigned int uint;
19typedef unsigned long long unll;
20typedef long long ll;
21typedef long double ld;
22
23template< typename T = int >
24inline T read(void);
25
26int N;
27int a[110];
28int dp[110][110];
29int cal(int s, int t){
30 int cnt(0);
31 for(int i = s; i <= t; ++i)if(a[i] != i - s)++cnt;
32 return cnt;
33}
34
35int main(){
36 memset(dp, 0x3f, sizeof dp);
37 dp[0][0] = 0;
38 N = read();
39 for(int i = 1; i <= N; ++i)a[i] = read();
40 for(int i = 0; i <= N; ++i)
41 for(int j = 1; j <= N; ++j)
42 for(int k = i + 1; k <= N; ++k)
43 dp[k][j] = min(dp[k][j], dp[i][j - 1] + cal(i + 1, k));
44 for(int i = 1; i <= N; ++i)printf("%d\n", dp[N][i]);
45 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
46 return 0;
47}
48
49template < typename T >
50inline T read(void){
51 T ret(0);
52 short flag(1);
53 char c = getchar();
54 while(c != '-' && !isdigit(c))c = getchar();
55 if(c == '-')flag = -1, c = getchar();
56 while(isdigit(c)){
57 ret *= 10;
58 ret += int(c - '0');
59 c = getchar();
60 }
61 ret *= flag;
62 return ret;
63}
存在
对于样例,有
Input_1
xxxxxxxxxx
114
Output_1
xxxxxxxxxx
116
一道纯粹的人类智慧题。。。
然后我们这里定义的循环周期并不是一般圆周运动绕一圈的操作次数,而是一头原来在第
首先对于符合条件的排列,有好几个奇怪的性质:
证明:因为是符合条件的排列,我们假设序列中最高的层数为
证明:显然某一时刻第
证明:考虑由性质一,第
证明:由性质二不难得出
以此我们便可以得出结论:
证明:首先枚举层数最小的平台有
此时根据我们前面的性质一定有标号相同的点值相同,那么此时
然后此时我们还要考虑,为什么仅枚举是否为
随便举几个例子可以发现这个结论似乎正确,那么我们现在尝试严谨一点地去证明,有结论,对于所有非
首先考虑如果有非
所以换一个说法理解,我们枚举的便为此处是
然后发现数据范围这个柿子肯定过不去,于是考虑优化,继续推柿子:
这个式子应该是可以继续推下去直到严格
显然我们可以通过分解质因数求欧拉函数,具体地,令
那么:
然后我们答案式子枚举的是 long long
。然后过程中是需要先让 long long
,当然像我一样直接用 __int128_t
可以直接忽略这些问题。
至此此题解决,还是很精妙的。
xxxxxxxxxx
861
2
3
4
5
6
7
8
9
10
11using namespace std;
12using namespace __gnu_pbds;
13
14mt19937 rnd(random_device{}());
15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
16bool rnddd(int x){return rndd(1, 100) <= x;}
17
18typedef unsigned int uint;
19typedef unsigned long long unll;
20typedef long long ll;
21typedef long double ld;
22
23
24
25template< typename T = int >
26inline T read(void);
27
28ll N;
29int tot(0);
30pair < ll, int > fact[1100000];
31int cur[1100000];
32__int128_t ans(0);
33
34__int128_t qpow(ll a, ll b){
35 __int128_t ret(1), mul(a);
36 while(b){
37 if(b & 1)ret = ret * mul % MOD;
38 b >>= 1;
39 mul = mul * mul % MOD;
40 }return ret;
41}
42
43void dfs(int p = 1, ll base = 1, __int128_t phi = 1, __int128_t div = 1){
44 if(p > tot){
45 phi *= base, phi /= div, phi %= MOD;
46 ans = (ans + phi * qpow(2, N / base) % MOD) % MOD;
47 return;
48 }
49 dfs(p + 1, base, phi, div);
50 phi *= fact[p].first - 1;
51 div *= fact[p].first;
52 for(int i = 1; i <= fact[p].second; ++i)
53 base *= fact[p].first, dfs(p + 1, base, phi, div);
54}
55
56int main(){
57 N = read < ll >();
58 ll tmp(N); ll cur(2), cnt(0);
59 while(tmp > 1){
60 if(cur * cur > tmp)break;
61 while(tmp % cur == 0)tmp /= cur, ++cnt;
62 if(cnt)fact[++tot] = {cur, cnt}, cnt = 0;
63 ++cur;
64 }if(tmp > 1)fact[++tot] = {tmp, 1};
65 dfs();
66 ans = ((((ans + 2 - N) % MOD) - qpow(2, N)) % MOD + MOD) % MOD;
67 printf("%lld\n", (ll)ans);
68 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
69 return 0;
70}
71
72template < typename T >
73inline T read(void){
74 T ret(0);
75 short flag(1);
76 char c = getchar();
77 while(c != '-' && !isdigit(c))c = getchar();
78 if(c == '-')flag = -1, c = getchar();
79 while(isdigit(c)){
80 ret *= 10;
81 ret += int(c - '0');
82 c = getchar();
83 }
84 ret *= flag;
85 return ret;
86}
奇怪题,先咕着,laterrrrrr 再来写。
Input_1
xxxxxxxxxx
11
Output_1
xxxxxxxxxx
11
xxxxxxxxxx
11
update-2022_11_10 初稿