『日常训练』2020WFU个人积分赛第三场

  1. D - 质因数分解【基础】

    签到题

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 1e5 + 5;
    bool f(int n){
        for(int i = 2; i*i <= n; i++){
            if(n%i==0) return 0;
        }
        return 1;
    }
    int main(void) {
        int n;
        cin >> n;
        for(int i = 2; i*i <= n; i++){
            if(n%i==0){
                int t = n/i;
                if(f(t)){
                    cout<<t<<endl;
                    break;
                }
            }
        }
        return 0;
    }
    
  2. F - Goldbach’s Conjecture【基础】

    签到题

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 1e5 + 5;
    bool f(int n){
        for(int i = 2; i*i <= n; i++){
            if(n%i==0) return 0;
        }
        return 1;
    }
    int main(void) {
        int n;
        while(cin>>n&&n){
            for(int i = 2; i <= n/2; i++){
                if(f(i)&&f(n-i)){
                    cout<<n<<" = "<<i<<" + "<<n-i<<endl;
                    break;
                }
            }
        }
        return 0;
    }
    
  3. G - Sherlock and His Girlfriend【思维】

    思路:质数输出0,合数输出1.

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 1e5 + 5;
    bool book[maxn];
    void Init(){
    	for(int i = 2; i <= maxn; i++){
    		if(book[i]==0){
    			for(int j = i+i; j <= maxn; j += i){
    				book[j] = 1;
    			}
    		}
    	}
    }
    int main(void) {
        int n;
        cin >> n;
        Init();
      	if(n==1){
    		cout<<1<<endl;
    		cout<<1<<endl;
    	}
    	else if(n==2){
    		cout<<1<<endl;
    		cout<<1<<" "<<1<<endl;
    	}
    	else{
    		cout<<2<<endl;
    		for(int i = 2; i <= n+1; i++){
    			if(book[i]==0) cout<<1<<" ";
    			else cout<<2<<" ";
    		}
    		cout<<endl;
    	}
        return 0;
    }
    
  4. E - 轻拍牛头【数论】

    思路:n^2做法是很好想的,显然会超时。怎么优化呢?类似与我们学过的打表求最大因子。我们可以存下所有数出现的次数,然后将所有他们的倍数加上他们的个数,最后记得减去一次自己重复加上的即可(这道题对时间复杂度要求挺高,暴力肯定过不了,哪怕是这串代码,也被卡cin)

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 1e6 + 5;
    int a[maxn];
    int b[maxn];
    int c[maxn];
    int main(void) {
        int n;
        cin >> n;
        int maxx = 0;
        for(int i = 1; i <= n; i++){
            cin >> a[i];
            b[a[i]]++;
            maxx = max(a[i],maxx);
        }
        for(int i = 1; i <= maxx; i++){
            if(b[i]==0) continue;
            for(int j = i; j <= maxx; j += i){
                c[j] += b[i];
            }
        }
        for(int i = 1; i <= n; i++){
            cout<<c[a[i]]-1<<endl;
        }
        return 0;
    }
    
  5. H - 樱花【数论-质因数分解】

    前置知识:阶乘分解

    思路:化简方程得
    x + y x y = 1 n ! \frac{x+y}{xy} = \frac{1}{n!}
    进一步得到
    x y ( x + y ) n ! = 0 xy-(x+y)*n!=0
    很多人会推到这被卡住了,我们两边同时加上 n 2 n^2
    n ! 2 n ! ( x + y ) + x y = n ! 2 n!^2-n!*(x+y)+xy=n!^2
    因式分解得到
    x n ! ) ( y n ! ) = n ! 2 (x-n!)(y-n!)=n!^2
    a = x n ! a=x-n! b = y n ! b=y-n! ,得到
    a b = n ! 2 ab=n!^2
    我们要求(x,y)的对数,我们发现只要求出a的个数即可,因为 a = n ! 2 / b a=n!^2/b ,b和a的个数是一样的。

    怎么求a呢?我们发现a是 n ! 2 n!^2 的一个因子,根据唯一分解定理,我们可以先把 n ! 2 n!^2 分解掉可得
    n ! = p 1 c 1 × p 2 c 2 × . . . × p k c k n!=p_1^{c_1}\times p_2^{c_2} \times ... \times p_k^{c_k}
    可得
    ( n ! ) 2 = p 1 2 c 1 × p 2 2 c 2 × . . . × p k 2 c k (n!)^2=p_1^{2c_1}\times p_2^{2c_2} \times ... \times p_k^{2c_k}
    那么根据唯一分解定理a的个数为
    ( 2 c 1 + 1 ) ( 2 c 2 + 1 ) . . . ( 2 c k + 1 ) (2c_1+1)(2c_2+1)...(2c_k+1)
    那么最后的答案即为:
    ( 2 c 1 + 1 ) ( 2 c 2 + 1 ) . . . ( 2 c k + 1 )   m o d   1 0 9 + 7 (2c_1+1)(2c_2+1)...(2c_k+1)\ mod\ 10^9+7
    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int mod = 1e9 + 7;
    const int maxn = 1e6+10;
    int num[maxn];
    int cnt,prime[maxn];
    bool vis[maxn];
    void Init(int n){
        for(int i = 2; i <= n; i++){
            if(!vis[i])
                prime[++cnt] = i;
            for(int j = 1; j <= cnt &&i*prime[j]<=n;j++){
                vis[i*prime[j]] = 1;
                if(i%prime[j] == 0)
                    break;
            }
        }
    }
    int main(void){
        int n;
        cin >> n;
        Init(n);
        for(int i = 1; i <= n; i++){
            int tmp = i;
            for(int j = 1; j <= cnt&&prime[j]*prime[j] <= tmp; j++){
                if(tmp%prime[j]==0){
                    int ct = 0;
                    while(tmp%prime[j] == 0){
                    	tmp /= prime[j];
    					ct++;
    				}
                    num[prime[j]] += ct;
                }
            }
            if(tmp>1)
                num[tmp]++;
        }
        ll ans = 1;
        for(int i = 1; i <= cnt; i++) ans = (ans*(2*num[prime[i]]+1))%mod;
        cout<<ans<<endl;
        return 0;
    }
    
  6. C - Prime Distance【素数筛】

    思路:显然,不可能直接去筛 2147483647 以内的素数;

    由于任何一个合数n必定包含一个不超过 n \sqrt{n} 的质因子,

    那么,我们不妨先用欧拉筛法筛出 [0,46341]区间内的素数(46341≈√2147483647);

    然后对于每个【L,R】区间,用筛出来的质数再去标记【L,R】内的合数,剩下来的就是质数了。

    细节之处,自己好好揣摩代码。

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6+10;
    bool book[maxn];
    bool vis[maxn];
    int a[maxn];
    typedef long long ll;
    ll l,r;
    void Init()
    {
    	memset(book,0,sizeof(book));
    	memset(vis,0,sizeof(vis));
    	for(ll i = 2; i*i <= r; i++)
    	{
    		if(vis[i]==0)
    		{
    			for(ll j = i+i; j*j <= r; j += i)
    				vis[j] = 1;
    			for(ll j = max(2ll,(l+i-1)/i)*i; j <= r; j += i)////(L-1+i/i)得到最接近L的i的倍数
    				book[j-l] = 1;////偏移量,因为单纯j会导致数组越界,把范围弄到0到len上
    		}
    	}
    }
    int main(void)
    {
    	
    	while(cin>>l>>r)
    	{
    		if(l==1)
    			l++;
    		Init();
    		int cnt = 0;
    		int flag = 0;
    		for(int i = 0; i <= r-l; i++)
    		{
    			if(book[i]==0)
    			{
    				flag = 1;
    				a[cnt++] = i+l;
    			}
    		}
    		if(flag==0||cnt==1)
    			cout<<"There are no adjacent primes."<<endl;
    		
    		else
    		{
    			ll minx = 0x3f3f3f3f;
    			ll maxx = -0x3f3f3f3f;
    			ll pos1,pos2;
    			ll q1,q2;
    			for(int i = 1; i < cnt; i++)
    			{
    				ll t = a[i]-a[i-1];
    				if(t<minx)
    				{
    					minx = t;
    					pos1 = a[i];
    					pos2 = a[i-1];
    				}
    				if(t > maxx)
    				{
    					maxx = t;
    					q1 = a[i];
    					q2 = a[i-1];
    				}
    			}
    			cout<<pos2<<","<<pos1<<" are closest, " <<q2<<","<<q1<<" are most distant."<<endl;
    		}
    	}
    	return 0;
    }
    
    
  7. A - Computer Game【模拟】

    PS:这是一道很好的模拟

    题意:你正在玩你最喜欢的一款游戏,现在你闯到了最后一关,要和大Boss一决高下。

    Boss有两个属性:生命值max和每秒钟回复的生命值reg。

    你手上有N个卷轴,每个卷轴也有两个属性:卷轴使用时Boss的最大血量百分比 p o w i pow_i (如果Boss的血量百分比大于 p o w i pow_i ,则无法使用这个卷轴)和卷轴每秒钟造成的伤害 d a m i dam_i 。卷轴是一次性的,但是它的效果会持续到游戏结束。

    每一秒钟战斗的顺序是:Boss先受到所有卷轴造成的伤害,然后回复reg点生命值(当然,Boss的血量不能超过max),然后你使用可以使用的一个卷轴。

    当某一秒Boss受到伤害并回复血量之后血量小于等于0时,你就赢了。

    现在请你回答:你是否能够赢这一局游戏?如果可以,求出最短用时、每一个卷轴是否被使用和使用过的卷轴被使用的时间。

    注意:在获胜的那一秒不能使用卷轴

    思路:模拟。。。

    AC代码:

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    int n,x,y,t[1010],id[1010],vis[1010];
    struct node{
        int id, p, d;
    }a[1010];
    bool cmp1(node a,node b){return a.d>b.d;}
    bool cmp2(node a,node b){return a.id<b.id;}
    int main()
    {
        scanf("%d%d%d",&n,&x,&y);
        for(int i=1;i<=n;i++){
            scanf("%d%d",&a[i].p,&a[i].d);
            a[i].id = i;
        }
        sort(a+1,a+1+n,cmp1);
        int now = x, d = 0, be = 0, cnt = 0;
        for(int i=0; ; i++){
            now -= d; now += y;
            now = min(now, x);
            if(now<=0){
                printf("YES\n%d %d\n",i,cnt);
                for(int j=0;j<cnt;j++) printf("%d %d\n",t[j],id[j]);
                return 0;
            }
            for(int j=1;j<=n;j++){
                if(vis[j]||a[j].p*x<now*100) continue;
                vis[j] = 1; d += a[j].d;
                t[cnt] = i; id[cnt++] = a[j].id;
                break;
            }
            if(be==d&&d<=y) break;
            be = d;
        }
        printf("NO\n");
        return 0;
    }
    
发布了8 篇原创文章 · 获赞 4 · 访问量 1521

猜你喜欢

转载自blog.csdn.net/wxd1233/article/details/105591362