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求强连通分量
  • 相关阅读:
    排球教练积分程序
    排球积分程序
    排球积分程序
    14周总结
    本周总结
    排球计分规则
    我与计算机
    排球计分程序
    《如何成为一个高手》观后感
    十八周总结
  • 原文地址:https://www.cnblogs.com/thmyl/p/7348645.html
Copyright © 2011-2022 走看看