2020 牛客多校第二场

https://ac.nowcoder.com/acm/contest/5667

RK:227

Solved:3 / 11

UpSolved:10 / 11


A、All with Pairs
B、Boundary

考虑同弦所对的圆周角相等,所以我们只需要先枚举一个点A,然后再枚举一个点B,计算∠ABO的大小,然后答案一定是组合数,算一下即可,不过这样存在一些方向上的问题,另一种做法就是先枚举两个点,计算这两个点与原点构成的圆的圆心,圆心的最大值一定是组合数,算一下即可得出答案,注意精度问题

https://ac.nowcoder.com/acm/contest/view-submission?submissionId=44299374

int ans;
vectorv;
int main()
{
	int n;
	sc("%d", &n);
	if (n == 1)
	{
		pr("1\n");
		return 0;
	}
	Point oo = Point{ 0,0 };
	for (int i = 1; i <= n; i++)
		que[i].input();
	for (int i = 1; i <= n; i++)
	{
		for (int j = i + 1; j <= n; j++)
		{
			if (sgn(cross(que[i], que[j], oo)) == 0)
				continue;
			circle o = circle{ oo, que[i], que[j] };
			v.push_back(o.p);
		}
	}
	sort(v.begin(), v.end());
	int cnt = 0, len = v.size();
	for (int i = 1; i < len; i++)
	{
		if (sgn(v[i].x - v[i - 1].x) == 0 && sgn(v[i].y - v[i - 1].y) == 0)
		{
			cnt++;
		}
		else
		{
			ans = max(ans, cnt);
			cnt = 1;
		}
	}
	ans = max(ans, cnt);
	int res = 1;
	while (res * (res - 1) / 2 != ans)
		res++;
	pr("%d\n", res);
}


C、Cover the Tree

一开始三个人讨论的时候,首先明确了连叶子结点,出来了一些接近答案的想法,然后无一例外,都被hack掉了,然后 jzk 提出了一个 dfs 序,然后也被 hack 掉了,然后 jzk 提出了左边一半连右边一半,多出来一个随便连,yp写了代码,过了

#include
using namespace std;
typedef long long ll;
const int MAX = 4e5+5;
const int INF = 0x3f3f3f3f;
int n,first[MAX],nextt[MAX],u[MAX],v[MAX],cnt,ans,du[MAX],dfn[MAX],tot;
vector list1;
void add(int a,int b){
    u[cnt]=a,v[cnt]=b;
    nextt[cnt]=first[u[cnt]];
    first[u[cnt]]=cnt;++cnt;
}
void dfs(int dot,int fa){
    dfn[dot]=++tot;
    for(int num = first[dot];num!=-1;num=nextt[num]){
        if(v[num]==fa) continue;
        dfs(v[num],dot);
    }
}
bool cmp(int a,int b){
    return dfn[a]

D、Duration

由于 jzk 没注意到比赛开始了,所以5分钟的时候才签上到

#include 
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
int main()
{
    int a, s, d, q, w, e;
    sc("%d:%d:%d %d:%d:%d", &q, &w, &e, &a, &s, &d);
    int ans1 = a * 3600 + s * 60 + d;
    int ans2 = q * 3600 + w * 60 + e;
    pr("%d\n", abs(ans1 - ans2));
}

E、Exclusive OR

有了一个快速沃尔什变换的板子,真香

题解给的做法是求出前19项即可,因为满秩的情况下最多18个数字异或最大,所以19的答案是不确定的,需要FWT求出答案,然后对于 n>=20 的答案 ans[n] = ans[n-2]

//https://ac.nowcoder.com/acm/contest/5667/E
//异或卷积  选1-n个数字,异或值最大,可重复选
#include 
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const ll mod = 1e9 + 7;
const ll inv2 = (mod + 1) / 2;
const int MAXN = (3e5 + 5) * 2;//最大值的两倍(fwt一倍空间也可?)
ll a[MAXN];
ll s[MAXN];
ll ans[MAXN];
void FWT_or(ll a[], int len, int opt)
{
    for (int i = 1; i < len; i <<= 1)
        for (int p = i << 1, j = 0; j < len; j += p)
            for (int k = 0; k < i; ++k)
                if (opt == 1)
                    a[i + j + k] = (a[j + k] + a[i + j + k]) % mod;
                else
                    a[i + j + k] = (a[i + j + k] + mod - a[j + k]) % mod;
}
void FWT_and(ll a[], int len, int opt)
{
    for (int i = 1; i < len; i <<= 1)
        for (int p = i << 1, j = 0; j < len; j += p)
            for (int k = 0; k < i; ++k)
                if (opt == 1)
                    a[j + k] = (a[j + k] + a[i + j + k]) % mod;
                else
                    a[j + k] = (a[j + k] + mod - a[i + j + k]) % mod;
}
void FWT_xor(ll a[], int len, int opt)
{
    for (int i = 1; i < len; i <<= 1)
        for (int p = i << 1, j = 0; j < len; j += p)
            for (int k = 0; k < i; ++k)
            {
                ll x = a[j + k], y = a[i + j + k];
                a[j + k] = (x + y) % mod;
                a[i + j + k] = (x + mod - y) % mod;
                if (opt == -1)
                {
                    a[j + k] = 1ll * a[j + k] * inv2 % mod;
                    a[i + j + k] = 1ll * a[i + j + k] * inv2 % mod;
                }
            }
}
void FWT(ll a[], int len, int opt)
{
    for (int i = 1; i < len; i <<= 1)
        for (int p = i << 1, j = 0; j < len; j += p)
            for (int k = 0; k < i; ++k)
            {
                ll x = a[j + k], y = a[i + j + k];
                a[j + k] = (x + y);//% mod;
                a[i + j + k] = (x - y);//% mod;
                if (opt == -1)
                {
                    a[j + k] = 1ll * a[j + k] / 2;// *inv2% mod;
                    a[i + j + k] = 1ll * a[i + j + k] / 2;// *inv2% mod;
                }
            }
}
void run(ll a[], ll b[], int len1, int len2)
{
    FWT(a, len1, 1);
    FWT(b, len2, 1);
    int lens = 1;//最大长度的两倍(fwt一倍也可?)
    while (lens < 2 * len1 || lens < 2 * len2)
        lens <<= 1;
    for (int i = 0; i < lens; i++)
        a[i] = a[i] * b[i];
    FWT(a, len1, -1);
    FWT(b, len2, -1);
}
int main()
{
    int n;
    sc("%d", &n);
    for (int i = 0; i < n; i++)
    {
        ll t;
        sc("%lld", &t);
        a[t] = 1;
        s[t] = 1;
        ans[1] = max(ans[1], t * 1LL);
    }
    for (int i = 2; i <= min(19, n); i++)
    {
        run(s, a, 1 << 18, 1 << 18);
        for (int j = 0; j < MAXN; j++)
        {
            if (s[j])
            {
                ans[i] = max(ans[i], j * 1LL);
                s[j] = 1;
            }
        }
    }
    for (int i = min(19, n) + 1; i <= n; i++)
        ans[i] = ans[i - 2];
    for (int i = 1; i <= n; i++)
        pr("%lld%c", ans[i], i == n ? '\n' : ' ');
}


F、Fake Maxpooling

开场 jzk 看了一眼,然后感觉不太可做,然后 dh 说直接单调队列扫两次就完了,然后 jzk 恍然大悟,卡了一下空间就A了,有一个问题,题解给了一个筛法求gcd,赛时的时候 jzk 也想到用筛法来优化 gcd,由于太菜写了错误的筛法,贡献了一发罚时

不过出题人给的筛法还是很nb的

#include 
#include 
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
int matrix[5005][5005];
int temp1[5005][5005];
int main()
{
    int n, m, k;
    sc("%d%d%d", &n, &m, &k);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (temp1[i][j] == 0) {
                for (int k = 1; k * i <= n && k * j <= m; k++) {
                    temp1[i * k][j * k] = k;
                }
            }
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            matrix[i][j] = i * j / temp1[i][j];
        }
    }
    for (int i = 1; i <= n; i++)
    {
        dequeq;
        for (int j = 1; j <= m; j++)
        {
            while (!q.empty() && matrix[i][q.back()] < matrix[i][j])
                q.pop_back();
            while (!q.empty() && j - q.front() + 1 > k)
                q.pop_front();
            q.push_back(j);
            if (j >= k)
                temp1[i][j - k + 1] = matrix[i][q.front()];
        }
    }
    //n m-k+1
    for (int j = 1; j <= m - k + 1; j++)
    {
        dequeq;
        for (int i = 1; i <= n; i++)
        {
            while (!q.empty() && temp1[q.back()][j] < temp1[i][j])
                q.pop_back();
            while (!q.empty() && i - q.front() + 1 > k)
                q.pop_front();
            q.push_back(i);
            if (i >= k)
                matrix[i - k + 1][j] = temp1[q.front()][j];
        }
    }
    //n-k+1 m-k+1
    ll ans = 0;
    for (int i = 1; i <= n - k + 1; i++)
    {
        for (int j = 1; j <= m - k + 1; j++)
            ans += 0LL + matrix[i][j];
    }
    pr("%lld\n", ans);
}


G、Greater and Greater
H、Happy Triangle
 I、Interval
J、Just Shuffle
K、Keyboard Free

学习自 https://www.cnblogs.com/wlzhouzhuan/p/13301358.html

大概做法就是固定点 A 在(1,0)上,然后考虑若 B 点确定,则可以积分求出点 C 到直线 AB 之间的距离,然后由于题目要求的精度要求比较小,所以可以考虑枚举 B 的位置,就是在 B 所在的圆中,等距离取若干个点,他们的平均值作为点 C 到直线 AB 之间的距离,然后面积就等于高度乘以底/2。

感觉难度大概在将整个图建模出来,和如何求出点 C 到直线 AB 之间的距离。

#include 
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const double PI = acos(-1.0);
int main() 
{
    int T;
    sc("%d", &T);
    while (T--) 
    {
        int r[3];
        sc("%d%d%d", &r[0], &r[1], &r[2]);
        sort(r, r + 3);
        double ans = 0;
        for (int i = 1; i <= 1000; i++)
        {
            double x = r[1] * cos(2 * PI / 1000 * i);
            double y = r[1] * sin(2 * PI / 1000 * i);
            double L = sqrt((x - r[0]) * (x - r[0]) + y * y);
            double H = y / L * r[0];
            double angle = asin(H / r[2]);
            double h = 4.0 * r[2] * (angle * sin(angle) + cos(angle)) / (2 * PI);
            ans += h * L / 2;
        }
        ans /= 1000.0;
        printf("%.1f\n", ans);
    }
}

 

你可能感兴趣的:(2020,牛客多校赛)