zoukankan      html  css  js  c++  java
  • 2021牛客寒假算法基础集训营1 补题 ABCEFIJ

    https://ac.nowcoder.com/acm/contest/9981#question

    A. 串

    考虑先搞出来一个串然后逐渐添加。设dp[i]为长度为i的含有us子串的串的个数,则当dp[i - 1]已经求出来的情况下,第i个位置:

    1. 前面已经有us,第i个位置随便添加

      dp[i] += dp[i - 1] * 26;

    2. 前面没有us,但出现过出现了u,当前位置必须出现s

      dp[i] += 26^(i - 1) - 25 ^ (i - 1) - dp[i - 1];即总数减去之前没有u的(i - 1位每一位都只有25种情况)减去之前有us的(dp[i - 1])

    计数:dp / 排列组合

    #include <iostream>
    #define mod 1000000007
    #define ll long long
    using namespace std;
    ll n, dp[1000005] = { 0 };//dp[i]为长度为i的包含us的串的数量
    ll fpow(ll a, ll b)
    {
        ll ans = 1;
        for (; b; b >>= 1)
        {
            if(b & 1)
                ans = ans * a % mod;
            a = a * a % mod;
        }
        return ans;
    }
    int main()
    {
        cin >> n;
        dp[0] = dp[1] = 0;
        dp[2] = 1;
        for (int i = 3; i <= n; i++)
        {
            dp[i] = dp[i - 1] * 26 % mod;
            dp[i] = (dp[i] + fpow(26, i - 1) + mod - fpow(25, i - 1) + mod - dp[i - 1]) % mod;
        }
        ll ans = 0;
        for (int i = 1; i <= n; i++)
        {
            ans = (ans + dp[i]) % mod;//统计答案
        }
        cout << ans;
        return 0;
    }
    

    B. 括号

    因为形如(((...)))这样的括号,如果有n层,那么就有(n^2)对匹配的括号。那么直接对k开方然后向下取整得到a,极限情况下得到的大约是sqrt(1e9)为31622,乘2后也不会超过100000,至于剩下的(k - a^2)对括号,可以对上面的(((...)))从左往右数(k - a^2)个左括号,然后插入一个右括号即可。

    #include <iostream>
    #include <cmath>
    #include <vector>
    using namespace std;
    int main()
    {
    	vector <char> v;
    	int k;
    	cin >> k;
    	if(!k) 
    	{
    		cout << '(';
    		return 0;
    	}
    	int a = (int)sqrt(k);
    	int res = k - a * a;
    	for(int i = 1; i <= a; i++) v.push_back('(');
    	for(int i = 1; i <= a; i++) v.push_back(')');
    	vector<char>::iterator it;
        int cnt = 0;
        for(it = v.begin(); it != v.end(); it++)
        {
            if((*it) == '(') cnt++;
    		if(cnt == res || cnt == a)
    		{
    			v.insert(it + 1, ')');
    			res -= cnt;
    			break;
    		}
    	}
    	if(res)
    	{
    		cnt = 0;
    		for (it = v.begin(); it != v.end(); it++)
    		{
         	   if((*it) == '(') cnt++;
    			if(cnt == res)
    			{
    				v.insert(it + 1, ')');
    				break;
    			}
    		}
    	}
    	for (int i = 0; i < v.size(); i++)
    		cout << v[i];
    	return 0;
    }
    

    C. 红和蓝

    从叶子结点开始分析。首先注意到一个点肯定不能有两个以上的叶子结点,因为设第一个叶子结点和父亲节点同色(满足染色要求),剩下的节点肯定都不能再与父亲节点同色,然而这样的话就无法满足它周围有与它同色的点的要求了。因此排除掉不可能的情况后,选择把所有的叶子结点与其父亲节点涂相同的颜色,同时与其他相邻的点异色。这样这些点确定后就可以去掉了,去掉之后得到的还是一棵树,同样满足这个要求,因此可以dfs,在回溯的时候:

    1. 这个点是叶子结点:标记其与父亲节点同色
    2. 这个点不是叶子结点同时没有被其儿子结点标记:标记其与其父亲节点同色。

    如果一个点没有被涂色但其父亲节点被涂色:无解

    如果没有儿子结点能把整棵树的根结点涂色(即除了根结点外都配对):无解

    #include <iostream>
    #define N 100005
    using namespace std;
    int n, head[N], ver[2 * N], Next[2 * N], f[N], color[N], tot = 0, cnt = 0;
    bool flag = 1;
    void add(int x, int y)
    {
        ver[++tot] = y, Next[tot] = head[x], head[x] = tot;
    }
    void dfs1(int x, int pre){
        int son = 0;
        for (int i = head[x]; i; i = Next[i])
        {
            int y = ver[i];
            if(y == pre)
                continue;
            son++;
            dfs1(y, x);
        }
        if(!son || f[x] == 0)
        {
            if(f[pre])
            {
                flag = 0;
                return;
            }
            f[x] = f[pre] = ++cnt;
        }
    }
    void dfs2(int x, int pre)
    {
        for (int i = head[x]; i; i = Next[i])
        {
            int y = ver[i];
            if(y == pre)
                continue;
            if(f[y] == f[x])
                color[y] = color[x];
            else
                color[y] = color[x] ^ 1;
            dfs2(y, x);
        }
    }
    int main(){
        cin >> n;
        for (int i = 1; i <= n - 1; i++){
            int x, y;
            cin >> x >> y;
            add(x, y);
            add(y, x);
        }
        dfs1(1, 0);//选取1为树根进行预处理
        if(f[0] != 0 || !flag)
        {
            cout << -1;
            return 0;
        }
        color[1] = 1;
        dfs2(1, 0);
        for (int i = 1; i <= n; i++)
        {
            if(color[i])
                cout << "R";
            else
                cout << "B";
        }
        return 0;
    }
    

    E. 三棱锥之刻

    高中数学几何题QAQ

    #include <iostream>
    #include <cmath>
    using namespace std;
    double a, r;
    const double PI = acos(-1.0);
    int main()
    {
        cin >> a >> r;
        if (r <= sqrt(6.0) / 12.0 * a)
        {
            cout << 0;
        }
        else if(r <= a / (2.0 * sqrt(2.0)))//球和三棱锥框架相切,此时形状为四个圆形
        {
            cout << 4.0 * PI * (r * r - 1.0 / 24 * a * a);//注意这里是1.0 不能写成1!!!
        } 
        else if(r <= sqrt(6.0) / 4.0 * a)//三棱锥内接于球
        {
            double rr = sqrt(r * r - 6.0 / 144 * a * a);
            double h = a / (2.0 * sqrt(3));
            double b = 2.0 * sqrt(rr * rr - h * h);
            double tri = b * h * 0.5;
            double sector = PI * rr * rr * (asin(b / (2 * rr)) * 2 / (2 * PI));
            double each = PI * rr * rr - 3 * (sector - tri);
            cout << 4 * each;
        }
        else
        {
            cout << sqrt(3) * a * a;
        }
        return 0;
    }
    

    F. 对答案一时爽

    签到题。

    #include <iostream>
    using namespace std;
    int n;
    char a[105], b[105];
    int main()
    {
    	int mmax = 0, mmin = 0;
    	cin >> n;
    	for(int i = 1; i <= n; i++)
    	{
    		cin >> a[i];
    	}
    	for(int i = 1; i <= n; i++)
    	{
    		cin >> b[i];
    	}
    	for(int i = 1; i <= n; i++)
    	{
    		if(a[i] == b[i])
    		{
    			mmax += 2;
    		}
    		else
    		{
    			mmax++;
    		}
    	}
    	cout << mmax << ' ' << mmin;
    	return 0;
    }
    

    I. 限制不互素对的排列

    首先看到k的范围比较特殊,联想到奇偶性。然后知道相邻两个奇数互素,相邻一奇一偶互素,启发我们把前面搞成相邻偶数,后面搞成相邻奇数,类似2 4 6... 1 3 5... 可以发现前面有n / 2个偶数,可以贡献n / 2 - 1对,因此k < n /2的情况已经可以构造出来了,那么需要特判k = n /2的情况,最简单的写法是把6和最后一个偶数位置互换,1和3位置互换。(代码写的是1和9(存在的话)互换然后加特判,挫了)

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    int n, k, a[100005];
    int main()
    {
        cin >> n >> k;
        for (int i = 1; i <= n; i++)
            a[i] = i;
        if(!k)
        {
            for (int i = 1; i <= n; i++)
                cout << a[i] << ' ';
            return 0;
        }
        if(n == 2)
        {
            cout << -1;
            return 0;
        }
        if(n == 3 || n == 4 && k == 2 || n == 5 && k == 2)
        {
            cout << -1;
            return 0;
        }
        if(n == 6 && k == 3)
        {
            cout << "2 4 6 3 1 5";
            return 0;
        }
        if(n == 7 && k == 3)
        {
            cout << "2 4 6 3 1 5 7";
            return 0;
        }
        if(n == 8 && k == 4)
        {
            cout << "8 2 4 6 3 1 5 7";
            return 0;
        }
        if(k == n / 2)
        {
            for (int i = 1; i <= k; i++)
                a[i] = 2 * i;
            for (int i = k + 1; i <= n; i++)
                a[i] = 2 * (i - k) - 1;
            if (n >= 9)
                swap(a[k + 1], a[k + 5]);
        }
        else
        {
            for (int i = 1; i <= k + 1; i++)
              a[i] = 2 * i;
            for (int i = 1; i <= k + 1; i++)
              a[k + 1 + i] = a[i] - 1;
            for (int i = 2 * k + 3; i <= n; i++)
               a[i] = i;
        }
        for (int i = 1; i <= n; i++)
            cout << a[i] << ' ';
        return 0;
    }
    
    

    然后这个题可以拓展成最长gcd序列:

    ![截屏2021-02-02 下午11.21.44](/Users/xiezhengyuan/Library/Application Support/typora-user-images/截屏2021-02-02 下午11.21.44.png)

    J. 一群小青蛙呱嘣呱嘣呱

    首先观察要求最小公倍数的数有什么样的特点。2划掉了2的k次方,3划掉了3的k次方...因此这些数必须有两个以上的质因子。

    (a=p_1^{a1}p_2^{a2}p_3^{a3}... b = p_1^{b1}p_2^{b2}p_3^{b3}),联想唯一分解定理,则(lcm(a, b) = p_1^{max(a1,b1)}p_2^{max(a2,b2)}p_3^{max(a3,b3)}...)

    因此考虑每个质数的贡献,即对于p, (p^x)的x最高能取到多少。对于2,为了使x最大化,只能:(2^x imes 3 <= n),因为取别的的话x就会变小。同理,其他素数p,只能:(p^x imes 2 <= n)

    #include <iostream>
    #include <cmath>
    #include <cstring>
    #define maxn 160000005
    #define mod 1000000007
    using namespace std;
    int v[maxn] = { 0 }, prime[maxn];
    int n, m, mmax = 0;
    int fpow(int a, int b)
    {
        int ans = 1;
        for (; b; b >>= 1)
        {
            if(b & 1)
                ans = ans * a % mod;
            a = a * a % mod;
        }
        return ans;
    }
    void primes(int nn)
    {
        v[0] = 0;
        m = 0;
        for (int i = 2; i <= nn; i++)
        {
            if(v[i] == 0)
            {
                v[i] = 1ll * i;
                prime[++m] = 1ll * i;
                if(i <= n)
                    mmax = max(mmax, m);
            }
            for (int j = 1; j <= m; j++)
            {
                if(prime[j] > v[i] || prime[j] > 1ll * nn / i)
                    break;
                v[i * prime[j]] = prime[j];
            }
        }
    }
    int main()
    {
        cin >> n;
        primes(80000000);
        long long ans = 1;
        for (int i = 1; i <= mmax; i++)
        {
            long long pre = ans;
            if (i == 1)
            {
                ans = ans * fpow(2, floor(log(n / 3) / log(prime[i]))) % mod;
            }
            else
            {
                ans = ans * fpow(prime[i], floor(log(n / 2) / log(prime[i]))) % mod;
            }
            if(ans == pre)
                break;
            //cout << ans << endl;
        }
        if(n < 6)
            cout << "empty";
        else
            cout << ans;
        return 0;
    }
    
  • 相关阅读:
    redux核心知识
    react性能优化要点
    react-router4的使用备注
    selenium启动Chrome配置参数问题
    Navicat15最新版本破解和破解报错总结
    Silence主题美化-部署
    vscode打开文件,中文显示乱码(已解决)
    Windows下Charles从下载安装到证书设置和浏览器抓包
    python下的selenium和chrome driver的安装
    Python 直接赋值、浅拷贝和深度拷贝解析
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/14387201.html
Copyright © 2011-2022 走看看