- 6737151's blog
施工现场
- 2024-3-12 9:20:18 @
对答案模 的余数 分类讨论。设每个周期季风位移为 ,终点矢量与 时刻季风位移矢量和的差为 。则问题转换为:考虑函数 ,求最小自然数 使得 。
考虑 是一个由 不超过 个折线段 构成的 凸函数。但我们不会分类讨论,考虑牛顿迭代法。具体而言:
初始时设指针 ,进入以下循环:
- 循环开始时,已知 ,。
- 若 ,答案为 ,退出循环。
- 若 ,根据函数凸性,,,故无解,退出循环。
- 假设答案在 所在折线段上,可知其为 (类似于找到当前折线段与 轴的交点)。
- 根据函数凸性,,。于是令 。
对于倒数第二步, 意味着 与 不在同一折线段上;而折线段个数不超过 ,对于每个余数求解时间为 ,总复杂度 。
#include <bits/stdc++.h>
#include <windows.h>
#include <conio.h>
using namespace std;
int a[1111][1111], vis[99999], mx[1111];
HDC Hdc = GetDC(GetConsoleWindow());
int mix(int ca, int cb, double rt){
int Ar=(ca>>16);
int Ag=((ca>>8)&((1<<8)-1));
int Ab=(ca&((1<<8)-1));
int Br=(cb>>16);
int Bg=((cb>>8)&((1<<8)-1));
int Bb=(cb&((1<<8)-1));
int R=int(floor(rt*double(Ar)+(1.0-rt)*double(Br)));
int G=int(floor(rt*double(Ag)+(1.0-rt)*double(Bg)));
int B=int(floor(rt*double(Ab)+(1.0-rt)*double(Bb)));
return (max(0,min(255,R))<<16)+(max(0,min(255,G))<<8)+max(0,min(255,B));
}
int L = 1;
void _(int x, int y, int c) {
x*=L; y*=L;
for (int i=0; i<L; ++i) {
for (int j=0; j<L; ++j) {
SetPixel(Hdc, x+i+30, y+j+30, c);
}
}
}
int main() {
system("color F0");
int cc=0, N=1000;
for (int i=0; i<=N; ++i) {
for (int j=0; j<=N; ++j) {
if (i>j) {
a[i][j]=a[j][i]; continue;
}
if ((i)||(j)) {
++cc;
for (int ii=0; ii<i; ++ii) vis[a[ii][j]]=cc;
for (int jj=0; jj<j; ++jj) vis[a[i][jj]]=cc;
for (int d=1; d<=min(i,j); ++d) vis[a[i-d][j-d]]=cc;
while (vis[a[i][j]]==cc) ++a[i][j];
}
mx[max(i,j)] = max(mx[max(i,j)],a[i][j]);
}
}
for (int i=1; i<=N; ++i) mx[i]=max(mx[i],mx[i-1]);
for (;;) {
for (int i=0; i<=N; ++i) {
for (int j=0; j<=N; ++j) {
if (!a[i][j]) _(i,j,0x000000);
else _(i,j,mix(0x0000EE,0xFFCC66,double(a[i][j])/double(mx[max(i,j)])));
}
}
}
return 0;
}
考场上比较好想的一个解法,也是目前最快解。
设 为所有 的最小公倍数, 为前 总物品填充 权值的方案数,。
枚举下标模 的余数 ,可观察到 是一个关于 的 次函数。分析完全背包递推过程,由于 ,有
$$f_{k,mx+r}=\sum_{p}[p\equiv r\ (\text{mod}\ w_i)]\sum_{y=0}^{x-[p>r]}f_{k-1,my+p} $$结合一个著名结论“, 是关于 的 次函数”,可以归纳证明这一点。
证明此结论后,解法便水落石出了。预处理 的值,然后可以拉格朗日插值求出任意 。设 中最小值为 ,观察到 ,于是按答案下标模 的值分别二分求解。
拉格朗日插值中精度损失很大,所以需要维护浮点型、取模整型各一个。
当然还有
.