• NOIP2016普及组复赛解题报告


    提高组萌新,DAY1DAY2加起来骗分不到300,写写普及组的题目聊以自慰。

    (附:洛谷题目链接

       T1:https://www.luogu.org/problem/show?pid=1909

       T2:https://www.luogu.org/problem/show?pid=2010

       T3:https://www.luogu.org/problem/show?pid=2058

       T4:https://www.luogu.org/problem/show?pid=2119)

    不得不说,亲历了14、15年的普及组,加上今年的题目,T1、T2难度简直爆炸性下滑、、、、、、直接贴下代码吧。(省略输入输出)

    T1

    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    int n,a[4],b[4],c[4];
    int main(){
        cin>>n;
        for(int i=1;i<=3;++i){
            scanf("%d%d",&a[i],&b[i]);
            c[i]=n/a[i]+1;
            if(n%a[i]==0)c[i]--;
            c[i]=c[i]*b[i];
        }
        cout<<min(c[1],min(c[2],c[3]));
        
        return 0;
    } 

    T2(无数种特殊情况、、、、、、写得非常繁琐,不过肯定有简洁很多的写法,只是这题目写得心烦意乱,懒得改了)

    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    int a,b,days[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
    int main(){
        int ans=0;
        cin>>a>>b;
        int year=a/10000;
        int moon=(a/100)%100;
        int date=a%100;
        int y=b/10000;
        int m=(b/100)%100;
        int d=b%100;
        if(a==b){
          if((a/10000000==a%10)&&(a/1000000%10==a%100/10)&&(a/100000%10==a%1000/100)&&(a/10000%10==a%10000/1000)){
                cout<<1;
                return 0;
          }
                cout<<0;
                return 0;
        }
        
        while(10000*year+100*moon+date<=b){
            int i=10000*year+100*moon+date;
            if((i/10000000==i%10)&&(i/1000000%10==i%100/10)&&(i/100000%10==i%1000/100)&&(i/10000%10==i%10000/1000)){
                ans++;
            }
            int runnian=0;
            if(((year%4==0)&&(year%100!=0))||(year%400==0))runnian=1;
            date=date+1;
            if((moon==2)&&(date==28+runnian)){
                date=1;
                moon=3;
            }
            if((moon!=2)&&(date==days[moon]+1)){
                date=1;
                moon=moon+1;
            }
            if(moon==13){
                moon=1;
                year=year+1;
            }    
        }
        cout<<ans;
    }

    T3

    出于一个蒟蒻的尿性,看到题目先想到去水70分,毕竟实战时时间有限,能骗一分是一分。

    看到数据范围先分析,n*x(i,j)=10^10,直接存每艘船的状态肯定拿不了满分,再看ti=10^9,按时间存状态肯定更加惨烈(应该没人这么想吧)。那么注意到Σki=3*10^5,这个地方很奇怪,它给的不是每艘船的人数,而是总人数,那么仔细一算,平均每艘船只有3个人!那么很容易(才怪,我想了半个小时以上,还是在有学长提醒的情况下完成的)就想到:按照每个人存储国际,记录每艘船的人的位置(从第几个人到第几个人),然后模拟一层过。代码如下

    #include<iostream>
    #include<cstdio>
    using namespace std;
    struct point{
        int country;
        int boat;         //boat属性其实没用,只是写的时候觉得记录了也不嫌多
    };point d[300030];    //d记录每个人的国籍
    
    int ans,sboat,tot,n,t[100010],k[100010],lef[100010],rig[100010],col[100010];  //n,ti,ki意思如题,lefi,rigi记录每艘船上的人在所有人中的位置(lefi到rigi)
    int main(){                                                                   //coli记录当前时刻及之前86400s每个国籍出现的人数(col=color)
        cin>>n;
        tot=0;            //记录第i艘船进入前的总人数,用于计算lefi和rigi
        for(int i=1;i<=n;++i){
            scanf("%d%d",&t[i],&k[i]);
            for(int j=1;j<=k[i];++j){
                int c;
                scanf("%d",&c);
                d[tot+j].country=c;
            }
            lef[i]=tot+1;
            tot+=k[i];
            rig[i]=tot;
        }
        sboat=1;ans=0;   //sboat记录第i艘船进入后统计范围内(86400s)的第1艘船,ans记录第i艘船进入后需要输出的答案,维护ans的值使得这道题不至于O(nx)
        for(int i=1;i<=n;++i){
            for(int j=lef[i];j<=rig[i];j++){
                if(col[d[j].country]==0)ans++;  //如果某个国籍在86400s内没有出现过,ans相比上一艘船+1
                col[d[j].country]++;
            }
            while(t[i]-t[sboat]>=86400){        //找到当前范围内的第一艘船,并更新各国籍出现人数
                for(int j=lef[sboat];j<=rig[sboat];j++){
                    col[d[j].country]--;
                    if(col[d[j].country]==0)ans--;
                }
                sboat++;
            }
            printf("%d
    ",ans);
        }
        
        return 0;
    }

    T4

    乍一看DFS可以水到部分分,先打为快,加上各种剪枝,最终结果洛谷评测55分。代码如下

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    struct magic{
        int num;
        int power;
    }; magic a[40040];
    
    int x[5],ans[40040][5],m,n;
    int comp(const magic&a,const magic&b){
        return(a.power<b.power);
    }
    void dfs(int k,int b){
        if(k==4){
            if(a[x[2]].power-a[x[1]].power==2*(a[x[4]].power-a[x[3]].power)){
                ans[a[x[1]].num][1]++;
                ans[a[x[2]].num][2]++;
                ans[a[x[3]].num][3]++;
                ans[a[x[4]].num][4]++;
            }
            return;    
        }
        for(int i=b;i<=m;++i){
            if((k!=0)&&(a[i].power==a[x[k]].power))continue;
            x[k+1]=i;
            if((k==2)&&(3*(a[x[2]].power-a[x[1]].power)>=a[x[3]].power-a[x[2]].power)){
                x[k+1]=0;
                continue;
            }
            if((k==2)&&(2*(a[m].power-a[x[3]].power)<a[x[2]].power-a[x[1]].power)){
                x[k+1]=0;
                break;
            }
            if((k==2)&&(2*(a[i+1].power-a[x[3]].power)>a[x[2]].power-a[x[1]].power)){
                x[k+1]=0;
                continue;
            }
            dfs(k+1,i+1);
            x[k+1]=0;
        }
        return;        
    }
    int main(){
        cin>>n>>m;
        for(int i=1;i<=m;++i){
            scanf("%d",&a[i].power);
            a[i].num=i;
        }
        sort(a+1,a+m+1,comp);
        dfs(0,1);
        for(int i=1;i<=m;++i){
            for(int j=1;j<=4;++j)printf("%d ",ans[i][j]);
            printf("
    ");
        }
        return 0;
    }

    但是55分并没有用,毕竟是在浙江这样高手如云的地区。分析数据,题目中给出了n,这很奇怪,在DFS中并没有用到n。并且看到n=15000,说明这道题要从n着手。

    再分析A,B,C,D的关系,设D-C=X,易得: B-A=2X; C-B>6X(注意这里不能取等);综合上述三式,可得A,B,C,D的数学关系:设A=i,则B=i+2X,C=i+8X+Y,

    D=i+9X+Y。因此可以想到一个n^2的算法,枚举i和X,而后事实证明K=1/9,N^2可以通过全部的点。(好吧,不得不承认,在做T4的时候,我无耻地翻了题解。

    附带链接:http://blog.csdn.net/c20181220_xiang_m_y/article/details/53258693)代码如下

    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    int n,m,k[40040],w[15050],a[15050],b[15050],c[15050],d[15050];
    int main(){
        cin>>n>>m;
        for(int i=1;i<=m;++i){
            scanf("%d",&k[i]);
            w[k[i]]++;
        }
        
        for(int i=1;9*i<n;++i){
            int s=0;
            for(int xd=9*i+2;xd<=n;++xd){
                s+=w[xd-9*i-1]*w[xd-7*i-1];
                d[xd]+=w[xd-i]*s;
                c[xd-i]+=w[xd]*s;
            }
            s=0;
            for(int xa=n-9*i-1;xa>=1;--xa){
                s+=w[xa+9*i+1]*w[xa+8*i+1];
                a[xa]+=w[xa+2*i]*s;
                b[xa+2*i]+=w[xa]*s;
            }
        }
        
        for(int i=1;i<=m;++i){
            printf("%d %d %d %d
    ",a[k[i]],b[k[i]],c[k[i]],d[k[i]]);
        }
    }
  • 相关阅读:
    asp.net web生命周期
    图的数据结构1
    最长公共子串
    内部排序

    棋盘覆盖问题
    队列
    矩阵连乘问题
    图的数据结构2
    旅行售货员问题
  • 原文地址:https://www.cnblogs.com/cxl681237/p/6098619.html
Copyright © 2020-2023  润新知