复旦勰码 3 月月赛 II Div2 题解
P10251 农场
所有矩形左侧的边的横坐标的最小值即为圈地左侧的边的横坐标的最小值,其他边同理。注意题目并不满足
剑指千星,问道苍冥。
#include <bits/stdc++.h> #define int long long int n,X1 = 1e9,Y1 = 1e9,X2 = -1e9,Y2 = -1e9; signed main(){ scanf("%lld",&n); for(int i = 1,x1,x2,y1,y2;i <= n;i ++){ scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2); X1 = std::min(X1,std::min(x1,x2)),Y1 = std::min(Y1,std::min(y1,y2)); X2 = std::max(X2,std::max(x1,x2)),Y2 = std::max(Y2,std::max(y1,y2)); } int num = (X2 - X1) * (Y2 - Y1); printf("%lld",num); return 0; }
P10252 线性变换
我的思路是特判一些情况:
由于此时我们已经满足
我们考虑最极限数据的时间复杂度,即当
雪境化三清域外,寸心系尘世万千。
#include <bits/stdc++.h> #define int long long int T,x,a,b; signed main(){ scanf("%lld",&T);while(T --){ scanf("%lld%lld%lld",&x,&a,&b); if(x == 0 or a == 0) printf("%lld\n",-b); else if(b == 0) printf("%lld\n",x); else if(a * x - b >= x) printf("%lld\n",x); else if(a == 1) printf("%lld\n",x - (x / b + 1) * b); else{ int num = a * x - b; while(1){ if(num < 0){printf("%lld\n",num);break;} num = num * a - b; } } } return 0; }
P10253 说唱
假设
于是我们容易得到一个结论:
因此我们先算出来
活下去...为了和我们一样的漂泊者,不再别离。
#include <bits/stdc++.h> #define N 500005 using namespace std; int T,a[N];string s; int main(){ scanf("%d",&T);while(T --){ cin >> s;if(s == "0") {puts("0");continue;} s = "0" + s;int c = 0,num = 0; for(int i = s.size() - 1;i >= 0;i --){ int J = s[i] - '0'; s[i] = (J * 9 + c) % 10 + '0'; c = (J * 9 + c) / 10; } if(s[0] == '0') s.erase(0,1);int cnt = (s.size() - 1) * 9; for(int i = 0;i < s.size() - 1;i ++) a[i + 1] = s[i] - '0',num -= a[i + 1]; num -= s[s.size() - 1] - '0'; while(cnt --){ a[s.size() - 1] ++;num -= 1; for(int i = s.size() - 1;i >= 1;i --){ if(a[i] != 10) break; a[i] = 0,a[i - 1] ++,num += 9; } num += 10; if(num >= 0) break; } if(num == 0){for(int i = 1;i <= s.size() - 1;i ++) printf("%d",a[i]);puts("");} else puts("-1"); } return 0; }
P10254 口吃
前置:排序不等式。
内容:设有两列数和 ,满足 , 。 是 的一个排列,则有:
。当且仅当 或 时等号成立。
语言描述:逆序和乱序和 顺序和。
证明:不妨设(若 则考虑 ),第 项 中 。
在乱序和中,我们调整第 项和第 项的位置,易知 ,故新的和 。
可能上面的式子有点不太易知,我们移项得到,由于 ,因此 ,合并同类项,可得 ,因此 ,因此 。
同理调整第项,得到 ,最多经过 次调整可得: 。
显然,当且仅当或 时等号成立。因此不等式右侧得证,左侧同理。
证毕。
那么本题中,我们可以根据排序不等式得到所有排列中最大的权值是
写到这里,我突然发现,好像用不到排序不等式,不需要知道那个
考虑对于一个排列
一个排好序的排列权值为
那么现在我们关键就在于求出这个
首先呢,我们需要先做一下这个题:P1521 求逆序对。即求出
我们定义
空山无归,春风不渡。
#include <bits/stdc++.h> #define N 5005 #define MOD 10000 using namespace std; int n,K,g[N][N]; int main(){ scanf("%d%d",&n,&K);g[0][0] = 1; for(int i = 1;i <= n;i ++){ g[i][0] = 1; for(int j = 1;j <= K;j ++){ for(int k = max(0,j - i + 1);k <= j;k ++){ g[i][j] = (g[i][j] + g[i - 1][k]) % MOD; } } } printf("%d",g[n][K]); return 0; }
回到本题,我们定义
前者好说,主要是后者。我们目前仍然是将
简单说一下求
与
最后结果为
此时我们的暴力代码就已经成型了:
他们的呼声,遗落为深谷中冗长的回音。
#include <bits/stdc++.h> #define int long long #define MOD 998244353 #define N 5005 using namespace std; int n,K,num,ans,g[N][N],f[N][N],dp[N][N]; signed main(){ scanf("%lld%lld",&n,&K);g[0][0] = 1; for(int i = 1;i <= n;i ++){ g[i][0] = 1; for(int j = 1;j <= K;j ++){ for(int k = max(0ll,j - i + 1);k <= j;k ++){ g[i][j] = (g[i][j] + g[i - 1][k]) % MOD; } } } for(int i = 1;i <= n;i ++){ for(int j = 1;j <= K;j ++){ for(int k = max(0ll,j - i + 1);k <= j;k ++){ f[i][j] = (f[i][j] + f[i - 1][k] + g[i - 1][k] * i * (j - k)) % MOD; } } } for(int i = 1;i <= n;i ++){ for(int j = 1;j <= K;j ++){ for(int k = max(0ll,j - i + 1);k <= j;k ++){ dp[i][j] = (dp[i][j] + dp[i - 1][k] + g[i - 1][k] * (n - i + 1) * (j - k)) % MOD; } } } for(int i = 1;i <= n;i ++) num += i * i; ans = ((num * g[n][K] % MOD + dp[n][K]) % MOD - f[n][K] + MOD) % MOD; printf("%lld",ans); return 0; }
然后呢,我们就使用前缀和优化一下,可以自己尝试找一下优化的方法,这里提供一种方法:
不想解释了,这个东西完全可以自己想出来怎么去优化,因为我们的
未曾被上苍注视的生命,亦将名姓写在天地之间。
#include <bits/stdc++.h> #define int long long #define MOD 998244353 #define N 5005 using namespace std; int n,K,num,ans,g[N][N],f[N][N],dp[N][N],s[N],cnt = -1; signed main(){ scanf("%lld%lld",&n,&K);g[0][0] = 1; for(int i = 1;i <= n;i ++){ g[i][0] = 1,cnt = -1; for(int j = 1;j <= K;j ++){ g[i][j] = (g[i][j - 1] + g[i - 1][j]) % MOD; if(j - i + 1 > 0){ cnt ++; g[i][j] = (g[i][j] - g[i - 1][cnt] + MOD) % MOD; } } } for(int i = 1;i <= n;i ++){ s[0] = 1 * i,cnt = -1; for(int j = 1;j <= K;j ++){ f[i][j] = (f[i][j - 1] + f[i - 1][j] + s[j - 1]) % MOD; s[j] = (s[j - 1] + g[i - 1][j] * i) % MOD; if(j - i + 1 > 0){ cnt ++; f[i][j] = (f[i][j] - (f[i - 1][cnt] + g[i - 1][cnt] * i * i) % MOD + MOD) % MOD; s[j] = (s[j] - (g[i - 1][cnt] * i) % MOD + MOD) % MOD; } } } for(int i = 1;i <= n;i ++){ s[0] = 1 * (n - i + 1),cnt = -1; for(int j = 1;j <= K;j ++){ dp[i][j] = (dp[i][j - 1] + dp[i - 1][j] + s[j - 1]) % MOD; s[j] = (s[j - 1] + g[i - 1][j] * (n - i + 1)) % MOD; if(j - i + 1 > 0){ cnt ++; dp[i][j] = (dp[i][j] - (dp[i - 1][cnt] + g[i - 1][cnt] * (n - i + 1) * i) % MOD + MOD) % MOD; s[j] = (s[j] - (g[i - 1][cnt] * (n - i + 1)) % MOD + MOD) % MOD; } } } for(int i = 1;i <= n;i ++) num += i * i; ans = ((num * g[n][K] % MOD + dp[n][K]) % MOD - f[n][K] + MOD) % MOD; printf("%lld",ans); return 0; }
但是此时还是不满足空间要求的。我们发现状态
修真者的仙途,何以由凡人的牺牲铸就?
#include <bits/stdc++.h> #define int long long #define MOD 998244353 #define N 45005 using namespace std; int n,K,num,ans,g[2][N],f[2][N],dp[2][N],s[N],cnt = -1,fl; signed main(){ scanf("%lld%lld",&n,&K);g[0][0] = 1; for(int i = 1;i <= n;i ++){ fl ^= 1; g[fl][0] = 1,cnt = -1; for(int j = 1;j <= K;j ++){ g[fl][j] = (g[fl][j - 1] + g[fl ^ 1][j]) % MOD; if(j - i + 1 > 0){ cnt ++; g[fl][j] = (g[fl][j] - g[fl ^ 1][cnt] + MOD) % MOD; } } s[0] = 1 * i,cnt = -1; for(int j = 1;j <= K;j ++){ f[fl][j] = (f[fl][j - 1] + f[fl ^ 1][j] + s[j - 1]) % MOD; s[j] = (s[j - 1] + g[fl ^ 1][j] * i) % MOD; if(j - i + 1 > 0){ cnt ++; f[fl][j] = (f[fl][j] - (f[fl ^ 1][cnt] + g[fl ^ 1][cnt] * i * i) % MOD + MOD) % MOD; s[j] = (s[j] - (g[fl ^ 1][cnt] * i) % MOD + MOD) % MOD; } } s[0] = 1 * (n - i + 1),cnt = -1; for(int j = 1;j <= K;j ++){ dp[fl][j] = (dp[fl][j - 1] + dp[fl ^ 1][j] + s[j - 1]) % MOD; s[j] = (s[j - 1] + g[fl ^ 1][j] * (n - i + 1)) % MOD; if(j - i + 1 > 0){ cnt ++; dp[fl][j] = (dp[fl][j] - (dp[fl ^ 1][cnt] + g[fl ^ 1][cnt] * (n - i + 1) * i) % MOD + MOD) % MOD; s[j] = (s[j] - (g[fl ^ 1][cnt] * (n - i + 1)) % MOD + MOD) % MOD; } } } for(int i = 1;i <= n;i ++) num += i * i; ans = ((num * g[fl][K] % MOD + dp[fl][K]) % MOD - f[fl][K] + MOD) % MOD; printf("%lld",ans); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】