NOIP模拟赛20161022

NOIP模拟赛2016-10-22 

题目名

东风谷早苗

西行寺幽幽子

琪露诺

上白泽慧音

源文件

robot.cpp/c/pas

spring.cpp/c/pas

iceroad.cpp/c/pas

classroom.cpp/c/pas

输入文件

robot.in

spring.in

iceroad.in

classroom.in

输出文件

robot.out

spring.out

iceroad.out

classroom.out

时间限制

1000MS

1000MS

1000MS

1000MS

内存限制

64MB

128MB

128MB

128MB

测试点

20

20

10

10

测试点分值

5

5

10

10


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);


很水的模拟  每一串命令位置变化是一样的

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=5005;
typedef long long ll;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int t,n,sx=0,sy=0,x=0,y=0,dx[300],dy[300];
char s[N];
int main(int argc, const char * argv[]){
    freopen("robot.in","r",stdin);
    freopen("robot.out","w",stdout);
    scanf("%s%d",s+1,&t);
     dx['E']=1;dy['E']=0;
     dx['S']=0;dy['S']=-1;
     dx['W']=-1;dy['W']=0;
     dx['N']=0;dy['N']=1;
     n=strlen(s+1);
    for(int i=1;i<=n;i++){
        sx+=dx[s[i]];sy+=dy[s[i]];
    }
    int k=t/n,b=t%n;
    while(k--){x+=sx;y+=sy;}
    for(int i=1;i<=b;i++){
        x+=dx[s[i]];y+=dy[s[i]];
    }
    printf("%d %d",x,y);
}



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


高精度除法 二分答案来试探

没用ll只有60分不开心,因为2e9+2e9还有*2e9都会溢出

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=2e4+5,INF=2e9;
typedef long long ll;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
struct big{
    ll l,d[N];
    big(){l=1;}
};
char s[N];
big a,b,c;
bool check(big &a,big &b){//a>=b
    if(a.l>b.l) return 1;
    if(a.l<b.l) return 0;
    for(int i=a.l;i>=1;i--){
        if(a.d[i]>b.d[i]) return 1;
        if(a.d[i]<b.d[i]) return 0;
    }
    return 1;
}
//void jian(big &a,big &b){
//    int g=0,l=b.l;
//    for(int i=1;i<=l;i++){
//        if(a.d[i]<b.d[i]){
//            a.d[i+1]--;
//            a.d[i]+=10;
//        }
//        a.d[i]-=b.d[i];
//    }
//    l++;
//    while(a.d[l]<0){a.d[l]+=10;a.d[l+1]--;l++;}
//    while(a.d[a.l]==0) a.l--;
//}
void cheng(big &a,ll b){
    ll g=0,l=a.l;
    for(int i=1;i<=l;i++){
        ll t=a.d[i]*b+g;
        a.d[i]=t%10;
        g=t/10;
    }
    l++;
    while(g){
        a.d[l]=g%10;
        g/=10;
        l++;
    }
    a.l=l-1;
}
void cpy(big &a,big &b){//a<---b
    a.l=b.l;
    for(int i=b.l;i>=1;i--) a.d[i]=b.d[i];
}
int main(){
    freopen("spring.in","r",stdin);
    freopen("spring.out","w",stdout);
    scanf("%s",s+1);
    int len=strlen(s+1);
    for(int i=1;i<=len;i++) a.d[len-i+1]=s[i]-'0';
    a.l=len;               //printf("l %d
",a.l);for(int i=a.l;i>=1;i--) printf("%c",a.d[i]+'0);
    scanf("%s",s+1);
    len=strlen(s+1);
    for(int i=1;i<=len;i++) b.d[len-i+1]=s[i]-'0';
    b.l=len;
    if(!check(a,b)) printf("0");
    else{
        ll l=1,r=INF,ans=-1;
        while(l<=r){//printf("%d %d
",l,r);
            ll m=(l+r)/2;
            cpy(c,b);
            cheng(c,m);   //printf("new
l %d m %d
",c.l,m);for(int i=c.l;i>=1;i--) printf("%c",c.d[i]+'0');cout<<"
";
            if(check(a,c)){ans=max(ans,m);l=m+1;}
            else r=m-1; 
        }
        printf("%d",ans);
    }
    
}



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


改了一下题目不要求路径

很明显DP,暴力的话n^2不行,然后想到了单调队列

对于i,用单调队列维护[i-r,i-l],然后入队i-l+1

因为只要超过n,所以最优解最远到N+r-1

f[i]表示到i的话有一个问题,不知道i这个店能不能从0到达,所以倒着来,答案就是f[0]

比赛时直接把w序列给倒过来了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=4e5+5;
typedef long long ll;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int n,l,r,w[N];
int f[N],q[N],head=1,tail=0;
void dp(){
    n=n+r-1;
    for(int i=1;i<=n/2;i++) swap(w[i],w[n-i+1]);
    for(int i=1;i<=n+1;i++){
        while(head<=tail&&q[head]<i-r) head++;
        if(head>tail) f[i]=w[i];
        else f[i]=f[q[head]]+w[i];
        int nw=i-l+1;
        if(nw>=0) while(head<=tail&&f[q[tail]]<f[nw]) tail--;
        q[++tail]=nw;
        //printf("%d %d  %d   %d %d
",i,w[i],f[i],q[head],q[tail]);
    }
}

int main(){
    freopen("iceroad.in","r",stdin);
    freopen("iceroad.out","w",stdout);
    n=read();l=read();r=read();
    for(int i=0;i<=n;i++) w[i]=read(); 
    dp();
    printf("%d",f[n+1]);
}



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行:若干个整数,依次输出最大的绝对连通区域所包含的村庄编号。

输入样例

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

     

第一眼,并查集、

第二眼,有向?!强连通分量.........完了tarjan完全忘了

打了一下暴力不太好做就弃疗了

60:floyd传递闭包+并查集维护

应该想到的

PS:字典序最小就是集合中最小点最小

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=5005,M=5e4+5;
typedef long long ll;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int n,m,a,b,flag,d[N][N];
void floyd(){
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                d[i][j]=d[i][j]||(d[i][k]&&d[k][j]);
}
int fa[N],mn[N],size[N];
inline int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int main(int argc, const char * argv[]){
    freopen("classroom.in","r",stdin);
    freopen("classroom.out","w",stdout);
    n=read();m=read();
    for(int i=1;i<=m;i++){
        a=read();b=read();flag=read();
        if(flag==1) d[a][b]=1;
        else d[a][b]=d[b][a]=1;
    }
    floyd();
    for(int i=1;i<=n;i++) fa[i]=mn[i]=i,size[i]=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(d[i][j]&&d[j][i]){//printf("%d %d
",i,j);
                int x=find(i),y=find(j);
                if(x!=y){
                    fa[y]=x;
                    mn[x]=min(mn[x],mn[y]);
                    size[x]+=size[y];//printf("f %d %d %d
",x,y,size[x]);
                }
            }
    int mx=0,ans;
    for(int i=1;i<=n;i++){
        if(size[i]>mx){mx=size[i];ans=i;}
        if(size[i]==mx&&mn[i]<mn[ans]) ans=i; 
    }
    printf("%d
",size[ans]);
    for(int i=1;i<=n;i++) if(d[i][ans]&&d[ans][i]) printf("%d ",i);
}

100分:tarjan求强连通分量

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=5005,M=5e4+5;
typedef long long ll;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
struct edge{
    int v,ne;
}e[M<<1];
int h[N],cnt=0;
inline void add(int u,int v){
    cnt++;
    e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt;
}
int n,m,a,b,flag;
int dfn[N],low[N],belong[N],size[N],dfc,scc;
int st[N],top=0;
void dfs(int u){//printf("dfs %d
",u);
    dfn[u]=low[u]=++dfc;
    st[++top]=u;
    for(int i=h[u];i;i=e[i].ne){
        int v=e[i].v;
        if(!dfn[v]){
            dfs(v);
            low[u]=min(low[u],low[v]);
        }else if(!belong[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        scc++;
        while(true){
            int x=st[top--];
            belong[x]=scc;
            size[scc]++;
            if(x==u) break;
        }
    }
}
int main(int argc, const char * argv[]){
    freopen("classroom.in","r",stdin);
    //freopen("classroom.out","w",stdout);
    n=read();m=read();
    for(int i=1;i<=m;i++){
        a=read();b=read();flag=read();
        if(flag==1){add(a,b);}
        else {add(a,b);add(b,a);}
    }
    for(int i=1;i<=n;i++) if(!belong[i]) dfs(i);
    int mx=0,ans;
    for(int i=1;i<=n;i++) if(size[belong[i]]>mx){
        mx=size[belong[i]];ans=belong[i];
    }
    printf("%d
",mx);
    for(int i=1;i<=n;i++) if(belong[i]==ans) printf("%d ",i); 
}
原文地址:https://www.cnblogs.com/candy99/p/5988410.html