• 智算之道复赛


    1.数字

    大意:输入aa和b,a的值是aa添加前面三位数字,问有多少种情况使得a0(modb),a没有前导0,long long int 范围。

    思路:枚举前面三位(100-999*相应倍数+aa)%b是否等于0

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long int ll;
    ll ipow(int bit){
        ll sum=1;
        for(int i=1;i<=bit;i++){
            sum*=10;
        }
        return sum;
    }
    int main(){
        ll temp,aa,b,a,sum=0;
        int bit=0;
        cin>>aa>>b;
        temp=aa;
        while(temp!=0){temp/=10;bit++;}
        for(int i=100;i<=999;i++){
            if((aa+i*ipow(bit))%b==0)sum++;
        }
        cout<<sum<<endl;
        return 0;
    }

    2.网络

    大意:普通格子(a,b)可以消耗w1个金币移动到(a+1,b)或(a,b+1),魔法格子多一个选择可以消耗w2个金币移动到(a+1,b+1),问从点(0,0)到(n,n)所消耗的最少金币。

    输入K个魔法格子,w1,w2。

    思路:用一个pair数组存储魔法格子,进行排序,保证从前往后,开一个dp数组存储到每个魔法格子的最小消耗,最后一个魔法格子添加为(n,n),初始值为全部选择w1的方式。

    算出两个魔法格子之间所需移动普通格子的距离-2(魔法格子可以用掉一次,步数-2)所消耗的金币与原先到达该点的消耗两者取最小值。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n,k,w1,w2,num;
    const int maxx=2005;
    ll f[maxx];
    pair<int,int>p[maxx];
    int main(){
        cin>>n>>k>>w1>>w2;
        for(int i=0;i<k;i++){
            cin>>p[i].first>>p[i].second;
        }
        if(w1*2<=w2){cout<<n*w1*2<<endl;return 0;}
        p[k]=make_pair(n,n);k++;
        sort(p,p+k);
        for(int i=0;i<k;i++){
            f[i]=(ll)(p[i].first+p[i].second)*w1;
        }
        for(int i=1;i<k;i++){
            for(int j=0;j<i;j++){
                if(p[i].first>p[j].first&&p[i].second>p[j].second){
                    num=p[i].first+p[i].second-p[j].first-p[j].second-2;
                    f[i]=min(f[i],f[j]+(ll)num*w1+w2);
                }
            }
        }
        cout<<f[k-1]<<endl;
        return 0;
    }

    3.有向无环图

    大意:给定k条路径,不得超过N个点(即n<=N)。生成1.....n的没有重边的有向无环图。输出点数和边数。

    思路:考虑一种完全的有向无环图,把图画成一条链,编号小的依次向编号大加边,可以发现当n=2时,路径数为1,

    n=3时,路径数为2,n=4时路径数为4。有路径数至多等于2^n-2,我们知道任何数都可以拆成2的幂次和相加。

    即我们可以将路径数转化为二进制拆分,对于相应的点进行添加,最终凑成目标的路径数。

    找到一个大于等于该数的2次幂,幂数即为编号数量+2,将k--(因为1到n就有一条路),二进制数k从低位到高位判断位数为1的需要添加i-n的边(i从2开始)

    不过代码只有60分后面tle,有空再来补。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long int ll;
    vector<pair<int,int> >v;
    int main(){
        ll k,n,cnt=2,temp=1;
        cin>>k>>n;
        while(temp<k){
           temp<<=1;
            cnt++;///编号点
        }
        //ll t=temp-k;
        for(int i=1;i<cnt;i++){
            for(int j=i+1;j<cnt;j++){
                v.push_back(make_pair(i,j));///先把cnt-1的点连好
            }
        }
        k=k-1;
        for(int i=1;i<cnt;i++){
            if(i==1)v.push_back(make_pair(i,cnt));///当等于1时有边1-cnt,即默认有1条路径
            else{
                if(((k>>(i-2))&1)){///比如k=7,k-1=6=0110,补3-5,4-5两条边
                    v.push_back(make_pair(i,cnt));
                }
            }
        }
        cout<<cnt<<" "<<v.size()<<endl;
        for(int i=0;i<v.size();i++){
            printf("%ld %ld
    ",v[i].first,v[i].second);
        }
        return 0;
    }

    4.分数

    大意:输入n,a,b。有一个序列1-n的倒数,每一次找编号最小的且分母不为1的数q,序列的每一个数乘以这个数的分母,直到每个数分母都为1。

    a=a*q+b。对a取模mod=2^32输出。

    思路:观察发现每次进行乘的数的编号,该数是可以拆成最小素数的幂次方,每次乘以的数q也即是这个最小的素数。

    如输入4,序列1,1/2,1/3,1/4。乘以的数分别是2,3,2。我们进行欧拉筛得到所有的素数,再将素数的幂次方进行标记祖先素数的位置。

    题目要求以编号最小的,所以依次从左往右遍历,如果是某个素数的幂次方,我们乘以这个素数,其余的数会在过程中被约分掉。

    一些小细节:mod=1ll>>32,忘记写ll导致出错。素数的幂次方num需要开ll,否则溢出re。数据范围是8e7。开两个8e7的数组会mle,所以素数的数组开小一点。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long int ll;
    const int maxx=8e7+7,maxn=5e7;
    int c[maxn],v[maxx],cnt;
    ll a,b,n;
    ll mod=1ll<<32;
    void init(){
        for(int i=2;i<maxx;i++){
            if(v[i]==0){
                c[++cnt]=i;
            }
            for(int j=1;j<=cnt&&i*c[j]<maxx;j++){
                v[i*c[j]]=1;
                if(i%c[j]==0)break;
            }
        }
    }
    int main(){
        cin>>n>>a>>b;
        init();
        for(int i=1;i<=n;i++)v[i]=0;
        for(int i=1;i<=cnt;i++){
            ll num=c[i];
            while(num<=n){
                v[num]=i;
                num*=c[i];
            }
        }
        for(int i=2;i<=n;i++){
            if(v[i]){
                a=(a*c[v[i]]%mod+b)%mod;
            }
        }
        cout<<a<<endl;
        return 0;
    }

     

  • 相关阅读:
    Elispse快捷键
    cannot connect to daemon at tcp:5037: cannot connect to 127.0.0.1:5037: 由于目标计算机积极拒绝,无法连接。 (10061)
    android studio如何连接夜神模拟器
    Default Activity Not Found解决方法
    Android ANR log trace日志文件分析
    使用trace文件分析ANR
    ANR日志分析
    并发容器
    git上tag的一些操作
    final关键字与不变性
  • 原文地址:https://www.cnblogs.com/mohari/p/13501983.html
Copyright © 2020-2023  润新知