牛客多校第二场补题
D-Duration
签到
F-Fake Maxpooling
先得求lcm矩阵
关于求\(lcm\)矩阵,一种方法是直接暴力枚举每一对\((i,j)\),然后暴力计算\(gcd(i,j),lcm(i,j)=i*j/gcd(i,j)\)
第二种是类似埃氏筛的思想,对于每一对互质的\((i,j)\),都去从1枚举一个k使得\(i*k<=n\) 并且 \(j*k<=m\),然后把每一对\((i*k,j*k)\)的gcd标记为k,这样筛的效率就很高了(接近线性)
最后得到lcm矩阵的复杂度就是\(O(nm)\),剩下就是求每个k*k的正子矩阵的最大值了
由于是区间最大值,两次滑动窗口即可(这个题stldeque没被卡)
#pragma GCC optimize(2)
#include
#define ll long long
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;
double pi = acos(-1);
const double eps = 1e-9;
const int inf = 1e9 + 7;
const int maxn = 5005;
int DP[maxn][maxn];
int A[maxn][maxn];
struct poi
{
int id;
ll num;
};
dequedeq;
int __gcd(int a, int b)
{
while (b)
{
ll tmp = b;
b = a % b;
a = tmp;
}
return a;
}
int main()
{
int n, m, k;
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
if (!DP[i][j])
for (int u = 1; u * i <= n && u * j <= m; u++)
DP[u * i][u * j] = u, A[u * i][u * j] = i * j * u;
}
for (int i = 1; i <= n; i++)
{
deq.clear();
int j = 1;
for (int j = 1; j <= m; ++j)
{
int tmp = A[i][j];
while (!deq.empty() && deq.front().id <= j - k)deq.pop_front();
while (!deq.empty() && tmp > deq.back().num)
deq.pop_back();
deq.push_back({ j,tmp });
DP[i][j] = deq.front().num;
}
}
ll ans = 0;
for (int j = k; j <= m; ++j)
{
deq.clear();
for (int i = 1; i <= n; ++i)
{
int tmp = DP[i][j];
while (!deq.empty() && deq.front().id <= i - k)deq.pop_front();
while (!deq.empty() && tmp > deq.back().num)
deq.pop_back();
deq.push_back({ i,tmp });
if (i >= k)
ans += deq.front().num;
}
}
printf("%lld\n", ans);
return 0;
}
C-Cover the Tree
比赛的时候有思路,忘记写了
先记录入度为1的点计数为sum,ans就是点数/2上取整;然后从入度不为1的点开始dfs,把每个入度为1的点的dfs记录下来,把i和sum / 2 + i连接起来就可以将所有的边覆盖(不太会证。。。画图举例吧)
#pragma GCC optimize(2)
#include
//#include
//#include
//#include
//#include
//#include
//#include
#define ll long long
#define fastio {ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);};
using namespace std;
double pi = acos(-1);
const double eps = 1e-9;
const int inf = 1e9 + 7;
const int maxn = 1e6 + 10;
const ll mod = 998244353;
vectorG[maxn];
int sum = 0;
int n;
vectorxu;
void dfs(int from, int last)
{
if (G[from].size() == 1)
{
xu.push_back(from);
return;
}
for (int i = 0; i < G[from].size(); i++)
{
int to = G[from][i];
if (to != last)
dfs(to, from);
}
}
int main()
{
fastio;
cin >> n;
for (int i = 1; i < n; i++)
{
int a, b;
cin >> a >> b;
G[a].push_back(b);
G[b].push_back(a);
}
for (int i = 1; i <= n; i++)
if (G[i].size() == 1)
sum++;
cout << (sum + 1) / 2 << endl;
for (int i = 1; i <= n; i++)
if (G[i].size() != 1)
{
dfs(i, -1);
break;
}
for (int i = 0; i < sum / 2; i++)
cout << xu[i] << " " << xu[sum - i - 1] << endl;
if (sum & 1)
cout << xu[sum / 2 ] << " " << xu[0] << endl;
return 0;
}
B-Boundary
计算几何,枚举每一个点i,得到与圆心连线所对的弦对应的弧,利用同弧所对的圆周角相同,再去枚举另一个点j,将∠oji存下来,其中的众数就是ans
#pragma GCC optimize(2)
#include
#define ll long long
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;
double pi = acos(-1);
const double eps = 1e-12;
const int inf = 1e9 + 7;
const int maxn = 2e5 + 10;
int read()
{
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c>'9') { if (c == '-') f = -1; c = getchar(); }
while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + c - '0', c = getchar();
return f * x;
}
inline int dcmp(double x)//cmp x with 0
{
if (fabs(x) <= eps)return 0;
return x < 0 ? -1 : 1;
}
inline int cmp(double x, double y)
{
//x>y return 1
//x 0 ? x : y;
}
double min(double x, double y)
{
return dcmp(x - y) < 0 ? x : y;
}
struct Point {
double x, y;
Point() {}
Point(double xx, double yy) { x = xx; y = yy; }
Point operator -(Point s) { return Point(x - s.x, y - s.y); }
Point operator +(Point s) { return Point(x + s.x, y + s.y); }
double operator *(Point s) { return x * s.x + y * s.y; }
double operator ^(Point s) { return x * s.y - y * s.x; }
}p[2010];
double len(Point a) { return sqrt(a * a); }
double dis(Point a, Point b) { return len(b - a); }//两点之间的距离
double cross(Point a, Point b, Point c)//叉乘,a为公共点
{
return (b - a) ^ (c - a);
}
double dot(Point a, Point b, Point c)//点乘 ,a为公共点
{
return (b - a) * (c - a);
}
double angle(Point a, Point b, Point c)//求两个向量的夹角(余弦定理),a为公共点
{
return acos(dot(a, b, c) / dis(b, a) / dis(c, a));
}
bool Cmp(double x, double y)
{
if (cmp(x, y) == -1)return 1;
return 0;
}
vectorrad;
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
double x, y;
scanf("%lf %lf", &x, &y);
p[i] = { x,y };
}
if (n == 1)
{
printf("1\n");
return 0;
}
Point O = { 0.0,0.0 };
int ans = 1;
for (int i = 1; i <= n; i++)
{
rad.clear();
for (int j = 1; j <= n; j++)
{
if (cross(O, p[i], p[j]) < 0)
rad.push_back(dot(p[j], O, p[i]) / (dis(p[j], p[i]) * dis(p[j], O)));
}
sort(rad.begin(), rad.end(), Cmp);
int size = rad.size();
for (int l = 0, r; l < size; l = r)
{
for (r = l; r < size && cmp(rad[l], rad[r]) == 0; r++);
ans = max(ans, r - l + 1);
}
}
printf("%d\n", ans);
return 0;
}