• YAOI Round #5 题解


    前言

    比赛链接:

    Div.1 : http://47.110.12.131:9016/contest/13

    Div.2 : http://47.110.12.131:9016/contest/12

    Div.2——Charlotte

    下面是 Div.2 的题解。

    A. 我思及他人

    对于 (10\%) 的数据,枚举 (A,B,C) 判断即可,时间复杂度 (O(n^3))

    对于 (30\%) 的数据,枚举 (A,B) 判断 (C) 是否合法即可,时间复杂度 (O(n^2))

    对于 (50\%) 的数据,枚举 (C) 计算它对答案的贡献即可,时间复杂度 (O(n))

    对于 (100\%) 的数据,我们考虑把上面对 (C) 贡献的计算用数学方法搞成这样一个式子:(只用到了等差数列的求和公式)

    [ans=sum_{i=1}^{R-2 imes L+1}i=frac{(R-2 imes L+1)cdot(R-2 imes L+2)}{2} ]

    这样的时间复杂度为 (O(1)),即可通过本题。

    if(R-L-L<0) printf("0
    ");
    else printf("%lld
    ",(R-L-L+1)*(R-L-L+2)/2);
    

    B. 恋情与火焰

    这题应该算是道送分题——输出 No(60) 分。(当然乱搞还可以得到更多的分)

    但实际上正解也不算很难。

    (m)(a_i) 中的最小值,(M)(a_i) 中的最大值,(cnt)(a_i)(m) 出现的次数。

    • 首先有一个显然的结论:若 (M-m>1),则不存在合法的构造方案。

    • 考虑另一种比较简单的结论:若 (M-m=0),则当且仅当 (cnt=n-1)(2 imes cntleq n) 时存在合法的构造方案。

    事实上,我们会发现:(n) 个人中的颜色要么全都不同,要么就不存在某种颜色只出现了一次。

    当颜色全都不同时,(cnt=n-1);当不存在某种颜色只出现了一次时,(2 imes cntleq n)

    • 最后来看这样一个结论:若 (M-m=1),则当且仅当 (m<cnt)(n-cnt<2 imes (M-cnt))存在合法构造方案。

    我们考虑 (cnt) 的本质意义:只出现一次的颜色数量。

    对于一个颜色只出现一次的人来说,他能看到除自己以外所有只出现一次的颜色,有 (cnt-1) 种。

    同时他还能看到至少一种出现多次的颜色,所以他至少应该看到 (cnt) 种颜色。

    于是合法的构造要满足 (mgeq cnt)

    类似地,对于一个颜色出现多次的人来说,他可以看到当前的所有颜色,所以 (M) 是颜色总数。

    那么 (M-cnt) 就是出现多次颜色的数量。

    而出现多次的颜色至少要有两个,那么此时就需要满足 (n-cntgeq 2 imes (M-cnt)) 才有合法方案。

    根据上述三个结论便可得到正解。

    #include<bits/stdc++.h>
    #define Re register
    using namespace std;
    
    const int N=100005;
    int n,a[N];
    int cnt,Max,Min=0x3f3f3f3f;
    
    int main()
    {
    	scanf("%d",&n);
    	for(Re int i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    		Max=max(Max,a[i]);
    		Min=min(Min,a[i]);
    	}
    	for(Re int i=1;i<=n;i++)
    	{
    		if(a[i]==Min)
    		{
    			cnt++;
    		}
    	}
    	if(Max-Min>1) return 0*puts("No");
    	if(Max==Min)
    	{
    		if(Min==n-1||2*Min<=n) return 0*puts("Yes");
    		else return 0*puts("No");
    	}
    	if(Min<cnt||n+cnt<2*Max) return 0*puts("No");
    	return 0*puts("Yes");
    }
    

    C. 未曾留意的幸福

    (x=left(prodlimits_{i=1}^{n}a_i ight)-1) 可得 (f(x)=left(sumlimits_{i=1}^{n}a_i ight)-n)

    这样 (O(n)) 计算即可。

    scanf("%d",&n);
    for(Re int i=1;i<=n;i++)
    {
    	scanf("%d",&a);
    	ans+=a;
    }
    printf("%d",ans-n);
    

    D. 不在此处的世界

    考虑 (operatorname{lcm}(x,y)) 可能取到的最小值。

    实际上,取 (x=L,y=2 imes L) 得到 (operatorname{lcm}(x,y)=2 imes L) 为最小值。

    这样 (O(1)) 计算即可。

    if(r<2*l) puts("-1 -1");
    else printf("%d %d
    ",l,2*l);
    

    E. 你我的约定

    把每个 pair 写作 ((a_i,b_i))((-a_i,-b_i)) 的形式。

    那个符号的组合意义就变成是 ((a_i,b_i))((-a_j,-b_j)) 的折路径个数。

    于是就可以在平面上 DP 来一起统计:设 (f_{i,j}) 表示 ((i,j)) 到它左下角的点的路径总数。

    那么有 (f_{i,j}=f_{i-1,j}+f_{i,j-1}+cnt_{i,j}),搞定。

    Div.1——某科学的超电磁炮

    下面是 Div.1 的题解。

    A. RAILGUN

    同 Div.2 的 A 题。

    B. 御坂妹妹

    答案就是两倍总边长减去树的直径。

    这个比较显然,你手模一下,发现整棵树绝大多数边都需要遍历两遍,除了其中一条路径,那么当然减去直径最合算。

    C. 白井黑子

    同 Div.2 的 B 题。

    D. 上条当麻

    答案为:(P^{(n-1)^2}),因为你枚举左上的 (n-1) 行和 (n-1) 列的结果,有这么多种。

    于是你可以求得 (A_{i,n}=Pcdot(N-1)-sum_{j=1}^nA_{i,j})(A_{n,i}) 也同理。

    对于 (A_{n,n}),你会惊奇地发现没有冲突!

    注意:(C) 是没有用的,实现的时候,模数只能对 (998244353-1) 取模。

    inline void solve()
    {
        long long n, c, m; cin >>n >>c >>m;
        cout << qpow(m % 998244353, (n - 1) % 998244352 * ((n - 1) % 998244352) % 998244352) << endl;
    }
    

    E. 信仰不灭

    这个是 SG 函数的模板应用,如果不会的话可以看一下 SG 函数的 oi-wiki,代码如下:

    #include <bits/stdc++.h>
    
    using namespace std; typedef long long ll; const int maxn = 5e6 + 1e2;
    
    int n, cnt, SG[maxn]; unordered_map<ll, int> id;
    
    inline ll get(int x, int y) { return x * 100000ll + y; }
    
    int DFS(int x, int y)
    {
    	//cerr << x << ' ' << y << ' ' << cnt <<  endl;
    	if (x + y >= n) return 0; int u, v;
    	if (u = id[get(x, y)]) return SG[u]; u = id[get(x, y)] = ++cnt;
    	v = DFS(1, x + y); if (!v) SG[u] = 1;
    	v = DFS(x * 2, y); if (!v) SG[u] = 1;
    	v = DFS(x * 3, y); if (!v) SG[u] = 1; return SG[u];
    }
    
    
    extern "C" int _opt(int nn, int x, int y)
    {
    	n = nn, DFS(1, 0);
    	if (!SG[id[get(1, x + y)]]) return 1;
    	if (!SG[id[get(x * 2, y)]]) return 2;
    	if (!SG[id[get(x * 3, y)]]) return 3;
    	return -1;
    }
    
    int main()
    {
    	int n, a, b; cin >> n >>a >>b;
    	cout << _opt(n, a, b) << endl;
    }
    
  • 相关阅读:
    java反射机制
    java的hashmap与hashtable说明,简单易理解
    awk
    python的w+到底是什么
    hive深入浅出
    【OpenCV新手教程之十五】水漫金山:OpenCV漫水填充算法(Floodfill)
    对你相同重要的非技术贴,10件事证明你跟错了人
    SVM中为何间隔边界的值为正负1
    pushlet服务端推送——多播
    谁洗碗,搭载我的技术目标,起航。
  • 原文地址:https://www.cnblogs.com/kebingyi/p/14466107.html
Copyright © 2020-2023  润新知