zoukankan      html  css  js  c++  java
  • 2014-9-9 NOIP模拟赛

    东方幻想乡系列模拟赛
    Stage 1
    命题 Nettle
    审题 Barty ccy1991911 FlanS39 Wagner

    T2
    高精除高精,从来没写过,不知道怎么写,我就用大数减小数ans次,果断超时。
    T4
    Tarjan的板子题,好久没写,中间出现了一些小错误
        ①是尽管有双向边,Tarjan函数中也不必排除双向边
        ②Tarjan算法有时候不能一步完成,需要做最多n次,用循环解决
        ③问题是关于这个题目的虽然输入n代表有n个点,但是下面的连边中有些点根本没出现过,所以设一个数组记录有效点。
    View Code

    Problem 1 东风谷早苗(robot.cpp/c/pas)

    题目描述 在幻想乡,东风谷早苗是以高达控闻名的高中生宅巫女。某一天,早苗终于入手了最新款的
    钢达姆模型。作为最新的钢达姆,当然有了与以往不同的功能了,那就是它能够自动行走,
    厉害吧 (好吧, 我自重) 。 早苗的新模型可以按照输入的命令进行移动, 命令包含’E’、 ’S’、 ’W’、 ’N’
    四种,分别对应四个不同的方向,依次为东、南、西、北。执行某个命令时,它会向着对应
    方向移动一个单位。作为新型机器人,自然不会只单单执行一个命令,它可以执行命令串。
    对于输入的命令串,每一秒它会按照命令行动一次。而执行完命令串最后一个命令后,会自
    动从头开始循环。在 0 时刻时早苗将钢达姆放置在了(0,0)的位置,并且输入了命令串。她想要
    知道 T 秒后钢达姆所在的位置坐标。
    输入格式 第 1 行:一个字符串,表示早苗输入的命令串,保证至少有 1 个命令
    第 2 行:一个正整数 T
    输出格式 第 1 行:两个整数,表示 T 秒时,钢达姆的坐标
    输入样例 NSWWNSNEEWN
    12
    输出样例 -1 3
    数据范围 对于 60%的数据:T <= 500,000 且命令串长度 <= 5,000
    对于 100%的数据:T <= 2,000,000,000 且命令串长度<= 5,000
    注意 向东移动,坐标改变改变为(X+1,Y);
    向南移动,坐标改变改变为(X,Y-1);
    向西移动,坐标改变改变为(X-1,Y);
    向北移动,坐标改变改变为(X,Y+1);

    /*
        由于命令串是重复执行的,所以我们可以先计算出一个周期后机器人的移动量。比如在第一个周期后,机器人从(0,0)移动到(△X,△Y),那么每个周期之后机器人坐标改变为(X+△X,Y+△Y)。设 T/N = A…B,那么机器人一共会运行的周期数为 A,所以在 A 个周期后,机器人的坐标为(A*△X,A*△Y)。之后机
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int x,y,t,bei;
    char ch[5010];
    int main(){
        freopen("robot.in","r",stdin);
        freopen("robot.out","w",stdout);
        scanf("%s%d",ch+1,&t);
        int len=strlen(ch+1);
        for(int i=1;i<=len;i++){
            if(ch[i]=='E')x++;
            if(ch[i]=='S')y--;
            if(ch[i]=='W')x--;
            if(ch[i]=='N')y++;
        }
        bei=t/len;
        x*=bei;y*=bei;
        int len2=t%len;
        for(int i=1;i<=len2;i++){
            if(ch[i]=='E')x++;
            if(ch[i]=='S')y--;
            if(ch[i]=='W')x--;
            if(ch[i]=='N')y++;
        }
        printf("%d %d",x,y);
    }
    100分

    Problem 2 西行寺幽幽子(spring.cpp/c/pas)


    题目描述 在幻想乡,西行寺幽幽子是以贪吃闻名的亡灵。不过幽幽子可不是只会吃,至少她还管理着
    亡灵界。话说在幽幽子居住的白玉楼有一颗常年不开花的樱树——西行妖。幽幽子决定去收集
    人间的春度,聚集起来让西行妖开花。很快,作为幽幽子家园艺师的魂魄妖梦收集到了 M 个
    单位的春度。并且在这段时间里,幽幽子计算出要让西行妖开出一朵花需要 N 个单位的春度。
    现在幽幽子想要知道,使用所有的春度,能够让西行妖开出多少朵花。
    输入格式 第 1 行:一个正整数 M
    第 2 行:一个正整数 N
    N,M 的位数不超过 L,L 的范围在题目后面给出
    输出格式 第 1 行:一个整数 ans,表示能开出花的朵数
    输入样例 73861758
    12471
    输出样例 5922
    数据范围 对于 60%的数据:L <= 2,000 且 ans <= 2,000
    对于 100%的数据:L <= 20,000 且 ans <= 2,000,000,000
    2010-9-11 Touhou Contest Stage 1 By Nettle
    第 3 页 / 共 4 页

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn=20010;
    int ans;
    struct node{
        int len;
        int zu[maxn];
    }m,n;
    char M[maxn],N[maxn];
    bool compare(){
        if(m.len==1&&m.zu[1]==0)return 1;
        if(m.len==0)return 1;
        if(m.len<n.len)return 1;
        if(m.len>n.len)return 0;
        for(int i=1;i<=m.len;i++){
            if(m.zu[i]>n.zu[i])return 0;
            if(m.zu[i]<n.zu[i])return 1;
        }return 0;
    }
    node jian(){
        node res;
        //memset(res,0,sizeof(res));
        res.len=0;
        for(int i=1;i<=m.len;i++)res.zu[i]=0;
        for(int i=n.len,j=m.len;i>=1;i--,j--){
            if(m.zu[j]<n.zu[i]){
                m.zu[j]+=10;
                m.zu[j-1]--;
            }
            m.zu[j]-=n.zu[i];
        }
        for(int i=m.len;i>=2;i--){
            if(m.zu[i]<0){
                m.zu[i]+=10;
                m.zu[i-1]--;
            }
        }
        int start=1;
        for(int i=1;i<=m.len;i++)
            if(m.zu[i]!=0){
                start=i;
                break;
            }
        for(int i=start;i<=m.len;i++)
            res.zu[++res.len]=m.zu[i];
        return res;
    }
    int main(){
        freopen("spring.in","r",stdin);
        freopen("spring.out","w",stdout);
        scanf("%s%s",M+1,N+1);
        m.len=strlen(M+1);
        n.len=strlen(N+1);
        for(int i=1;i<=m.len;i++)m.zu[i]=M[i]-'0';
        for(int i=1;i<=n.len;i++)n.zu[i]=N[i]-'0';
        while(1){
            if(compare())break;//如果m比n小结束 
            m=jian();
            ans++;
        }
        printf("%d",ans);
    }
    60分 从 0 开始枚举累加,直到当前值超过了 N。
    /*二分答案*/
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    long long a[100010],a1[100010];
    struct node{
        int len,zu[100010];
        node operator * (const long long &now) const {
            node res;res.len=0;
            memset(a,0,sizeof(a));
            memset(a1,0,sizeof(a1));
            for(int i=1,j=len;i<=len;i++,j--)a[i]=zu[j];
            for(int i=1;i<=len;i++){
                a1[i]+=a[i]*now;
                a1[i+1]+=a1[i]/10;
                a1[i]%=10;
            }
            int len1=len;
            while(a1[len1+1]){
                len1++;
                a1[len1+1]+=a1[len1]/10;
                a1[len1]%=10;
            }
            res.len=len1;
            for(int i=len1,j=1;i>=1;i--,j++)res.zu[j]=a1[i];
            return res;
        }
    }m,n,Now;
    bool compare(){
        if(Now.len<m.len)return 1;
        if(Now.len>m.len)return 0;
        for(int i=1;i<=m.len;i++){
            if(Now.zu[i]<m.zu[i])return 1;
            if(Now.zu[i]>m.zu[i])return 0;
        }
        return 1;
    }
    char M[20010],N[20010];
    int main(){
        freopen("spring.in","r",stdin);
        freopen("spring.out","w",stdout);
        //freopen("Cola.txt","r",stdin);
        scanf("%s%s",M+1,N+1);
        int len1=strlen(M+1),len2=strlen(N+1);
        m.len=len1;n.len=len2;
        for(int i=1;i<=len1;i++)m.zu[i]=M[i]-'0';
        for(int i=1;i<=len2;i++)n.zu[i]=N[i]-'0';
        long long l=0,r=2000000000,ans;
        while(l<=r){
            long long mid=(l+r)/2;
            Now=n*mid;
            if(compare()){//如果now<=m 
                ans=mid;
                l=mid+1;
            }
            else r=mid-1;
        }
        printf("%lld",ans);
    }
    100分 二分答案

    Problem 3 琪露诺(iceroad.cpp/c/pas)


    题目描述 在幻想乡,琪露诺是以笨蛋闻名的冰之妖精。某一天,琪露诺又在玩速冻青蛙,就是用冰把
    青蛙瞬间冻起来。但是这只青蛙比以往的要聪明许多,在琪露诺来之前就已经跑到了河的对
    岸。于是琪露诺决定到河岸去追青蛙。小河可以看作一列格子依次编号为 0 到 N,琪露诺只能
    从编号小的格子移动到编号大的格子。而且琪露诺按照一种特殊的方式进行移动,当她在格
    子 i 时,她只会移动到 i+L 到 i+R 中的一格。你问为什么她这么移动,这还不简单,因为她是
    笨蛋啊。每一个格子都有一个冰冻指数 A[i],编号为 0 的格子冰冻指数为 0。当琪露诺停留在
    那一格时就可以得到那一格的冰冻指数 A[i]。琪露诺希望能够在到达对岸时,获取最大的冰冻
    指数,这样她才能狠狠地教训那只青蛙。但是由于她实在是太笨了,所以她决定拜托你帮它
    决定怎样前进。开始时,琪露诺在编号 0 的格子上,只要她下一步的位置编号大于 N 就算到
    达对岸。
    输入格式 第 1 行:3 个正整数 N, L, R
    第 2 行:N+1 个整数,第 i 个数表示编号为 i-1 的格子的冰冻指数 A[i-1]
    输出格式 第 1 行:一个整数,表示最大冰冻指数。保证不超过 2^31-1
    第 2 行:空格分开的若干个整数,表示琪露诺前进的路线,最后输出-1 表示到达对岸
    输入样例 5 2 3
    0 12 3 11 7 -2
    输出样例 11
    0 3 -1
    数据范围 对于 60%的数据:N <= 10,000
    对于 100%的数据:N <= 200,000
    对于所有数据 -1,000 <= A[i] <= 1,000 且 1 <= L <= R <= N
    注意 此题采用 Special Judge

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n,a[400010],dp[400010],l,r,g[400010];
    void show(int now){
        
        if(g[now])show(g[now]);
        if(now<=n)
        printf("%d ",now);
    }
    int main(){
        freopen("iceroad.in","r",stdin);
        freopen("iceroad.out","w",stdout);
        scanf("%d%d%d",&n,&l,&r);
        for(int i=0;i<=n;i++)scanf("%d",&a[i]);
        for(int i=1;i<=n+(r-l+1);i++){
            for(int j=l;j<=r;j++){
                if(i-j>=0){
                    if(dp[i]<dp[i-j]+a[i]){
                        dp[i]=dp[i-j]+a[i];
                        g[i]=i-j;
                    }
                }
            }
        }
        int ans=0,mark=0;
        for(int i=n;i<=n+(r-l+1);i++){
            if(dp[i]>ans){
                ans=dp[i];
                mark=i;
            }
        }
        cout<<ans<<endl;
        show(mark);
        if(mark>n)cout<<-1;
    }
    60分 未优化dp
    /*单调队列优化dp*/
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int inf = 0x3f3f3f3f;
    int n,l,r,a[200010],q[200010],head,tail,dp[200010],g[200010];
    int st[200010],top;
    int main(){
        //freopen("Cola.txt","r",stdin);
        freopen("iceroad.in","r",stdin);
        freopen("iceroad.out","w",stdout);
        scanf("%d%d%d",&n,&l,&r);
        for(int i=0;i<=n;i++)scanf("%d",&a[i]);
        head=1;tail=0;
        for(int i=1;i<=n;i++){
            dp[i]=-inf;
            if(q[head]==i-r-1&&head<=tail)head++;
            if(i-l>=0){
                while(dp[i-l]>dp[q[tail]]&&tail>=head)tail--;
                q[++tail]=i-l;
            }
            if(head<=tail){
                dp[i]=dp[q[head]];
                g[i]=q[head];
            }
            dp[i]+=a[i];
        }
        int mx=-inf,mark;
        for(int i=n-r+1;i<=n;i++)
            if(dp[i]>mx){
                mx=dp[i];
                mark=i;
            }
        printf("%d
    0 ",dp[mark]);
        while(1){
            if(mark==0)break;
            st[++top]=mark;
            mark=g[mark];
        }
        for(int i=top;i>=1;i--)printf("%d ",st[i]);
        printf("-1");
    }
    100分 单调队列优化dp

    Problem 4 上 白泽慧音(classroom.cpp/c/pas)


    题目描述 在幻想乡,上白泽慧音是以知识渊博闻名的老师。春雪异变导致人间之里的很多道路都被大
    雪堵塞,使有的学生不能顺利地到达慧音所在的村庄。因此慧音决定换一个能够聚集最多人
    数的村庄作为新的教学地点。人间之里由 N 个村庄(编号为 1..N)和 M 条道路组成,道路分
    为两种一种为单向通行的,一种为双向通行的,分别用 1 和 2 来标记。如果存在由村庄 A 到
    达村庄 B 的通路,那么我们认为可以从村庄 A 到达村庄 B,记为(A,B)。当(A,B)和(B,A)同时满足
    时,我们认为 A,B 是绝对连通的,记为<A,B>。绝对连通区域是指一个村庄的集合,在这个集
    合中任意两个村庄 X,Y 都满足<X,Y>。现在你的任务是,找出最大的绝对连通区域,并将这个绝
    对连通区域的村庄按编号依次输出。 若存在两个最大的, 输出字典序最小的, 比如当存在 1,3,4
    和 2,5,6 这两个最大连通区域时,输出的是 1,3,4。
    输入格式 第 1 行:两个正整数 N,M
    第 2..M+1 行:每行三个正整数 a,b,t, t = 1 表示存在从村庄 a 到 b 的单向道路,t = 2 表示村庄
    a,b 之间存在双向通行的道路。保证每条道路只出现一次。
    输出格式 第 1 行: 1 个整数,表示最大的绝对连通区域包含的村庄个数。
    第 2 行:若干个整数,依次输出最大的绝对连通区域所包含的村庄编号。
    2010-9-11 Touhou Contest Stage 1 By Nettle
    第 4 页 / 共 4 页
    输入样例 5 5
    1 2 1
    1 3 2
    2 4 2
    5 1 2
    3 5 1
    输出样例 3
    1 3 5
    数据范围 对于 60%的数据:N <= 200 且 M <= 10,000
    对于 100%的数据:N <= 5,000 且 M <= 50,000

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n,m,head[100010],num,belong[5010],ans2[5010],ans1[5010],ans[5010];
    int sz[5010],dfn[5010],low[5010],st[5010],cnt,top,group;
    int ans_num=0,mx=0;
    bool vis[5010],ask[5010],appear[5010];
    struct node{
        int pre,to;
    }e[100010];
    void Insert(int from,int to){
        e[++num].to=to;
        e[num].pre=head[from];
        head[from]=num;
    }
    void Tarjan(int v){
        
        low[v]=dfn[v]=++cnt;st[++top]=v;
        vis[v]=1;
        for(int i=head[v];i;i=e[i].pre){
            int to=e[i].to;
            if(ask[to])continue;
            if(!dfn[to]){
                Tarjan(to);
                low[v]=min(low[to],low[v]);
            }
            else if(low[v]>dfn[to]){
                if(vis[v])low[v]=dfn[to];
            }
        }
        if(dfn[v]==low[v]){
            group++;
            while(st[top]!=v){
                belong[st[top]]=group;ask[st[top]]=1;
                vis[st[top]]=0;
                sz[group]++;
                top--;
            }
            sz[group]++;
            vis[v]=0;
            belong[v]=group;
            ask[v]=1;
            top--;
        }
    }
    bool compare(){
        for(int i=1;i<=mx;i++)
            if(ans1[i]>ans2[i])return 1;
        return 0;
    }
    void Swap(){
        for(int i=1;i<=mx;i++)ans1[i]=ans2[i];
    }
    int main(){
        freopen("classroom.in","r",stdin);
        freopen("classroom.out","w",stdout);
        //freopen("Cola.txt","r",stdin);
        scanf("%d%d",&n,&m);
        int x,y,z;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&x,&y,&z);
            if(x==y)continue;
            appear[x]=appear[y]=1;
            if(z==1)Insert(x,y);
            if(z==2){
                Insert(x,y);
                Insert(y,x);
            }
        }
        
        for(int i=1;i<=n;i++){
            if(!ask[i]&&appear[i]){
                Tarjan(i);
            }
        }
        /*cout<<group<<endl;
        for(int i=1;i<=n;i++)
        cout<<belong[i]<<' ';*/
        for(int i=1;i<=group;i++){
            if(sz[i]>mx){
                ans_num=1;
                ans[ans_num]=i;
                mx=sz[i];
            }
            else if(sz[i]==mx){
                ans_num++;
                ans[ans_num]=i;
            }
        }
        printf("%d
    ",mx);
        int sum=0;
        for(int i=1;i<=ans_num;i++){//枚举每一种可能的答案 
            sum=0;
            for(int j=1;j<=n;j++){
                if(belong[j]==ans[i])
                    ans2[++sum]=j;
            }
            if(i==1||compare())Swap();//如果ans1的字典序比ans2大,那么交换过来 
        }
        for(int i=1;i<=mx;i++)printf("%d ",ans1[i]); 
    }
    100分 Tarjan求强连通分量
  • 相关阅读:
    第二次作业循环语句
    c语言01次作业分支,顺序结构
    PAT 1027. Colors in Mars
    PAT 1026 Table Tennis
    PAT 1035 Password
    PAT 1038. Recover the Smallest Number
    PAT 1028 List Sorting (25)
    PAT 1041 Be Unique (20)
    PAT 1025 PAT Ranking
    1037. Magic Coupon
  • 原文地址:https://www.cnblogs.com/thmyl/p/7348645.html
Copyright © 2011-2022 走看看