• 11.14 noip模拟试题


     

     

    题目名称

    正确答案

    序列问题

    长途旅行

    英文名称

    answer

    sequence

    travel

    输入文件名

    answer.in

    sequence.in

    travel.in

    输出文件名

    answer.out

    sequence.out

    travel.out

    时间限制

    1s

    1s

    1s

    空间限制

    256M

    256M

    256M

    测试点数目

    20

    20

    10

    测试点分值

    5

    5

    10

    是否有部分分

    题目类型

    传统

    传统

    传统

    是否有SPJ

    1.正确答案

    【题目描述】

    小H与小Y刚刚参加完UOIP外卡组的初赛,就迫不及待的跑出考场对答案。

    “吔,我的答案和你都不一样!”,小Y说道,”我们去找神犇们问答案吧”。

    外卡组试卷中共有m道判断题,小H与小Y一共从其他n个神犇那问了答案。之后又从小G那里得知,这n个神犇中有p个考了满分,q个考了零分,其他神犇不为满分或零分。这可让小Y与小H犯了难。你能帮助他们还原出标准答案吗?如有多解则输出字典序最小的那个。无解输出-1。

    【输入格式】

    第一行四个整数n, m, p, q,意义如上描述。

    接下来n行,每一行m个字符’N’或’Y’,表示这题这个神犇的答案。

    【输出格式】

    仅一行,一个长度为m的字符串或是-1。

    【样例输入】

    2 2 2 0

    YY

    YY

    【样例输出】

    YY

    【数据范围】

    30% : n <= 100.

    60% : n <= 5000 , m <= 100.

    100% : 1 <= n <= 30000 , 1 <= m <= 500.  0 <= p , q 且 p + q <= n.

     懒得写hash map水过

    #include<cstdio>
    #include<iostream>
    #include<map>
    #include<cstring>
    #include<algorithm>
    #define maxn 30010
    using namespace std;
    int n,m,p,q,falg;
    char ss[maxn];
    string s[maxn],ans;
    map<string,int>f;
    void Solve1(){
        for(int i=1;i<=n;i++){
            int x=f[s[i]];
            if(x!=p)continue;
            string now;now.clear();
            for(int k=0;k<m;k++)
                now+=(s[i][k]=='Y'?'N':'Y');
            int y=f[now];
            if(y==q){
                falg=1;ans=s[i];break;
            }
        }
    }
    void Solve2(){
        for(int i=1;i<=n;i++){
            int x=f[s[i]];
            if(x!=p)continue;
            string now;now.clear();
            for(int k=0;k<m;k++)
                now+=(s[i][k]=='Y'?'N':'Y');
            int y=f[now];
            if(y==q){
                falg=1;ans=s[i];break;
            }
        }
    }
    void Solve3(){
        for(int i=n;i>=1;i--){
            int x=f[s[i]];
            if(x!=q)continue;
            string now;now.clear();
            for(int k=0;k<m;k++)
                now+=(s[i][k]=='Y'?'N':'Y');
            int y=f[now];
            if(y==p){
                falg=1;ans=now;break;
            }
        }
    }
    void Solve4(){
        
        int A[510]={0};
        while(1){
            string now,noww;
            now.clear();noww.clear();
            for(int i=1;i<=m;i++)
                if(A[i])now+='Y';
                else now+='N';
            for(int i=1;i<=m;i++)
                if(A[i])noww+='N';
                else noww+='Y';
            int x=f[now],y=f[noww];
            if(!x&&!y){
                falg=1;ans=now;break;
            }
            int can=0;
            for(int i=m;i>=1;i--)
                if(A[i]==0){
                    A[i]=1;can=1;
                    for(int j=i+1;j<=m;j++)
                        A[j]=0;can=1;break;
                }
            if(!can)break;
        }
    }
    int main()
    {
        freopen("answer.in","r",stdin);
        freopen("answer.out","w",stdout);
        scanf("%d%d%d%d",&n,&m,&p,&q);
        for(int i=1;i<=n;i++){
            scanf("%s",ss);
            for(int j=0;j<m;j++)
                s[i]+=ss[j];
            f[s[i]]++;
        }    
        sort(s+1,s+1+n);
        if(p&&q)Solve1();
        else if(p&&!q)Solve2();
        else if(!p&&q)Solve3();
        else if(!p&&!q)Solve4();
        if(falg)cout<<ans<<endl;
        else cout<<"-1"<<endl;
        return 0;
    }
    View Code

    2.序列问题

    【题目描述】

    小H是个善于思考的学生,她正在思考一个有关序列的问题。

    她的面前浮现出了一个长度为n的序列{ai},她想找出两个非空的集合S、T。

    这两个集合要满足以下的条件:

    1. 两个集合中的元素都为整数,且都在 [1, n] 里,即Si,Ti ∈ [1, n]。

    2. 对于集合S中任意一个元素x,集合T中任意一个元素y,满足x < y。

    3. 对于大小分别为p, q的集合S与T,满足

                a[s1] xor a[s2] xor a[s3] ... xor a[sp] = a[t1] and a[t2] and a[t3] ... and a[tq].

    小H想知道一共有多少对这样的集合(S,T),你能帮助她吗?

    【输入格式】

           第一行,一个整数n

           第二行,n个整数,代表ai。

    【输出格式】

           仅一行,表示最后的答案。

    【样例输入】

    4

    1 2 3 3

    【样例输出】

    4

    【样例解释】

    S = {1,2}, T = {3}, 1 ^ 2 = 3 = 3 (^为异或)

    S = {1,2}, T = {4},  1 ^ 2 = 3 = 3

    S = {1,2}, T = {3,4}  1 ^ 2 = 3 & 3 = 3 (&为与运算)

    S = {3}, T = {4}  3 = 3 = 3

    【数据范围】

        30%: 1 <= n <= 10

        60%: 1 <= n <= 100

        100%: 1 <= n <= 1000, 0 <= ai < 1024

     30暴力

    /*暴力30*/
    #include<cstdio>
    #define maxn 1010
    using namespace std;
    int n,a[maxn],A[maxn],B[maxn],ans;
    void Dfs(int now,int x,int y){
        if(now==n+1){
            if(A[A[0]]>=B[1])return;
            if(x==y&&A[0]&&B[0])
            ans++;return;
        }
        Dfs(now+1,x,y);
        A[++A[0]]=now;Dfs(now+1,x^a[now],y);A[A[0]--]=0;
        B[++B[0]]=now;Dfs(now+1,x,y&a[now]);B[B[0]--]=0;
    }
    int main(){
        freopen("sequence.in","r",stdin);
        freopen("sequence.out","w",stdout);
        scanf("%d",&n);
        if(n>50){
            printf("0
    ");return 0;
        }
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        Dfs(1,0,1023);
        printf("%d
    ",ans);
        fclose(stdin);fclose(stdout);
        return 0;
    }
    View Code

    dp

    /*
    再一次没有写出dp来 感觉noip出个dp题要跪了22333
    这是个问题....
    想到了 f g 分别表示啥 
    然后发现 有重复 会重复计算很多
    然后发现可以定义成 一定选了这个的状态
    然后又有一个问题
    枚举分开点的话 又会漏了许多
    这就尴尬了.....
    解决方法是确定g选这个 然后f用前缀和
    嗯 很机智 
    */
    #include<cstdio>
    #include<cstring>
    #define maxn 1010
    using namespace std;
    int n,a[maxn],b[maxn];
    long long f[maxn][1024],g[maxn][1024],sum[1024],ans;
    int main()
    {
        freopen("sequence.in","r",stdin);
        freopen("sequence.out","w",stdout);
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)
            b[i]=a[n-i+1];
        for(int i=0;i<n;i++){
            for(int j=0;j<1024;j++)
                f[i+1][j^a[i+1]]+=sum[j];
            f[i+1][a[i+1]]++;
            for(int j=0;j<1024;j++)
                sum[j]+=f[i+1][j];
        }
        memset(sum,0,sizeof(sum));
        for(int i=0;i<n;i++){
            for(int j=0;j<1024;j++)
                g[i+1][j&b[i+1]]+=sum[j];
            g[i+1][b[i+1]]++;
            for(int j=0;j<1024;j++)
                sum[j]+=g[i+1][j];
        }
        memset(sum,0,sizeof(sum));
        for(int i=1;i<=n;i++){
            for(int j=0;j<1024;j++)
                sum[j]+=f[i][j];
            for(int j=0;j<1024;j++)
                ans+=sum[j]*g[n-i][j];
        }
        printf("%I64d
    ",ans);
        return 0;
    }
    View Code
    /*超时爆空间的压位高精  好吧dp写丑了 导致高精不好办了2333*/
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #define maxn 1001
    #define ll long long
    #define bas 1000000000
    using namespace std;
    int n,a[maxn],b[maxn];
    ll f[maxn][1024][40],g[maxn][1024][40],sum[1024][40],ans[40],A[40];
    void Add(ll a[40],ll b[40]){
        int len=max(a[0],b[0]),c[40]={0};
        for(int i=1;i<=len;i++)
            c[i]=a[i]+b[i];
        for(int i=1;i<=len;i++)
            if(c[i]>=bas){
                c[i+1]++;c[i]%=bas;
            }
        if(c[len+1])len++;c[0]=len;
        for(int i=0;i<=c[0];i++)a[i]=c[i];
    }
    void Mul(ll a[40],ll b[40]){
        memset(A,0,sizeof(A));
        for(int i=1;i<=a[0];i++){
            for(int j=1;j<=b[0];j++){
                A[i+j-1]+=a[i]*b[j];
                if(A[i+j-1]>=bas){
                    A[i+j]+=A[i+j-1]/bas;
                    A[i+j-1]%=bas;
                }
            }
            int len=i+b[0]-1;
            while(A[len+1]){
                len++;A[len+1]+=A[len]/bas;A[len]%=bas;
            }
        }
        for(int i=a[0]+b[0];i>=1;i--)
            if(A[i]){
                A[0]=i;break;
            }
    }
    int main()
    {
        freopen("sequence.in","r",stdin);
        freopen("sequence.out","w",stdout);
        cin>>n;
        for(int i=1;i<=n;i++)
            cin>>a[i];
        for(int i=1;i<=n;i++)
            b[i]=a[n-i+1];
        A[0]=1;A[1]=1;
        for(int i=0;i<n;i++){
            for(int j=0;j<1024;j++)
                Add(f[i+1][j^a[i+1]],sum[j]);
            Add(f[i+1][a[i+1]],A);
            for(int j=0;j<1024;j++)
                Add(sum[j],f[i+1][j]);
        }
        memset(sum,0,sizeof(sum));
        for(int i=0;i<n;i++){
            for(int j=0;j<1024;j++)
                Add(g[i+1][j&b[i+1]],sum[j]);
            Add(g[i+1][b[i+1]],A);
            for(int j=0;j<1024;j++)
                Add(sum[j],g[i+1][j]);
        }
        memset(sum,0,sizeof(sum));
        for(int i=1;i<=n;i++){
            for(int j=0;j<1024;j++)
                Add(sum[j],f[i][j]);
            for(int j=0;j<1024;j++){
                Mul(sum[j],g[n-i][j]);
                Add(ans,A);
            }
        }
        printf("%lld",ans[ans[0]]);
        for(int i=ans[0]-1;i>=1;i--)
            printf("%09lld",ans[i]);
        printf("
    ");
        return 0;
    }
    View Code

    (dp写丑了 导致高精炸了2333) 

    3.长途旅行

    【题目描述】

    JY是一个爱旅游的探险家,也是一名强迫症患者。现在JY想要在C国进行一次长途旅行,C国拥有n个城市(编号为0,1,2...,n - 1),城市之间有m条道路,可能某个城市到自己有一条道路,也有可能两个城市之间有多条道路,通过每条道路都要花费一些时间。JY从0号城市开始出发,目的地为n – 1号城市。由于JY想要好好参观一下C国,所以JY想要旅行恰好T小时。为了让自己的旅行更有意思,JY决定不在任何一个时刻停留(走一条到城市自己的路并不算停留)。JY想知道是否能够花恰好T小时到达n – 1号城市(每个城市可经过多次)。现在这个问题交给了你。

    若可以恰好到达输出“Possible”否则输出“Impossible”。(不含引号)。

    【输入格式】

    第一行一个正整数Case,表示数据组数。

           每组数据第一行3个整数,分别为n, m, T。

           接下来m行,每行3个整数x, y, z,代表城市x和城市y之间有一条耗时为z的双向边。

    【输出格式】

           对于每组数据输出”Possible”或者”Impossible”.

    【样例输入】

    2

    3 3 11

    0 2 7

    0 1 6

    1 2 5

    2 1 10000

    1 0 1

    【样例输出】

    Possible

    Impossible

    【样例解释】

           第一组:0 -> 1 -> 2 :11

           第二组:显然偶数时间都是不可能的。

    【数据范围】

           30%:  T <= 10000

    另有30%: n <= 5 , m <= 10.

           100%: 2 <= n <= 50 , 1 <= m <= 100 , 1 <= z <= 10000 , 1 <= T <= 10^18 , Case <= 5.

     暴力dp+骗分40

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<queue>
    #define maxn 51
    #define maxm 20010
    #define ll long long
    using namespace std;
    ll cas,n,m,T,G[maxn][maxn][110],f[maxm][maxn];
    ll vis[maxn],dis[maxn],diss[maxn],c[maxn];
    queue<ll>q;
    void Cl(){
        memset(G,0,sizeof(G));
        memset(f,0,sizeof(f));
    }
    void SPFA(){
        memset(dis,127/3,sizeof(dis));
        memset(vis,127/3,sizeof(vis));
        while(!q.empty())q.pop();
        vis[1]=1;dis[1]=0;q.push(1);
        while(!q.empty()){
            ll k=q.front();q.pop();
            vis[k]=1;if(c[k]>n+5)break;
            for(ll i=1;i<=n;i++)
                for(ll j=1;j<=G[k][i][0];j++){
                    ll v=i,t=G[k][i][j];
                    if(dis[v]>dis[k]+t){
                        dis[v]=dis[k]+t;
                        if(vis[v]==0){
                            q.push(v);vis[v]=1;c[v]++;
                        }
                    }
                }
        }
    }
    void SPFA2(){
        memset(diss,127/3,sizeof(diss));
        memset(vis,127/3,sizeof(vis));
        memset(c,0,sizeof(c));
        while(!q.empty())q.pop();
        vis[n]=1;diss[n]=0;q.push(n);
        while(!q.empty()){
            ll k=q.front();q.pop();
            vis[k]=1;if(c[k]>n+5)break;
            for(ll i=1;i<=n;i++)
                for(ll j=1;j<=G[k][i][0];j++){
                    ll v=i,t=G[k][i][j];
                    if(diss[v]>dis[k]+t){
                        diss[v]=dis[k]+t;
                        if(vis[v]==0){
                            q.push(v);vis[v]=1;c[v]++;
                        }
                    }
                }
        }
    }
    void Solve1(){
        f[0][1]=1;
        for(ll i=0;i<=T;i++)
            for(ll j=1;j<=n;j++)
                for(ll k=1;k<=n;k++)
                    for(ll l=1;l<=G[j][k][0];l++)
                        f[i+G[k][j][l]][j]=f[i][k]||f[i+G[k][j][l]][j];
        if(f[T][n])printf("Possible
    ");
        else printf("Impossible
    ");
    }
    void Solve2(){
        SPFA();ll falg=0;
        for(ll i=1;i<=n;i++)if(!falg)
            for(ll j=1;j<=n;j++)if(!falg)
                for(ll k=1;k<=G[i][j][0];k++){
                    ll x=dis[i],y=diss[j];
                    if((T-x-y-G[i][j][k])%(G[i][j][k]*2)==0){
                        falg=1;break;
                    }
                }
        if(falg)printf("Possible
    ");
        else printf("Impossible
    ");
    }
    int main()
    {
        freopen("travel.in","r",stdin);
        freopen("travel.out","w",stdout);
        cin>>cas;
        while(cas--){
            cin>>n>>m>>T;
            Cl();ll u,v,t;
            for(ll i=1;i<=m;i++){
                cin>>u>>v>>t;u++;v++;
                G[u][v][++G[u][v][0]]=t;
                G[v][u][++G[v][u][0]]=t;
            }
            if(T<=10000)Solve1();else Solve2();
        }
        fclose(stdin);fclose(stdout);
        return 0;
    }
    View Code
    /*
    30分的bfs很好想(然而奇葩的我写的dp...跑的好像很慢)
    那个状态是 dis[i][j] 1到i 经过时间j 存在不存在
    关键是 j 很大 状态会很大 时间会很慢 
    考虑重复走环的情况 假设 我们从0连出去一个环 大小为x
    那么这个环保证了一定能走 如果到 y 时刻能到 n-1 那么y ±x时刻也能到 
    根据这个性质 我们压缩第三维 %x 意义下 
    重定义状态dis[i][j]表示 1到 i 走的路程 s  s%x为j 且s最小
    那么最后的状态 dis[n-1][j] j==T%x 就只0 - n-1 走的路程余数为j的最短路 
    显然 走T的时间走到n-1的余数和走dis的余数相同 那么就有 dis+kx==T 意思就是
    在绕几遍x就好了 因为最后是+kx 所以尽量使dis小 跑最短路 
    */
    #include<cstdio>
    #include<iostream>
    #include<queue>
    #include<cstring>
    #define maxn 110
    #define maxm 50010
    #define ll long long
    using namespace std;
    ll cas,n,m,T,num,head[maxn],mx,dis[maxn][maxm],f[maxn][maxm];
    struct edge{
        ll v,t,pre;
    }e[maxn*2];
    struct node{
        ll x,s;
    };
    queue<node>q;
    void Cl(){
        num=0;mx=0x7fffffff;
        memset(f,0,sizeof(f));
        memset(head,0,sizeof(head));
        memset(dis,127/3,sizeof(dis));
    }
    void Add(ll from,ll to,ll dis){
        num++;e[num].pre=head[from];
        e[num].v=to;e[num].t=dis;
        head[from]=num;
    }
    void SPFA(){
        dis[1][0]=0;f[1][0]=1;
        q.push((node){1,0});
        while(!q.empty()){
            ll k=q.front().x;
            ll s=q.front().s;
            q.pop();f[k][s]=0;
            for(ll i=head[k];i;i=e[i].pre){
                ll v=e[i].v,y=s+e[i].t;y%=mx;
                if(dis[v][y]>dis[k][s]+e[i].t){
                    dis[v][y]=dis[k][s]+e[i].t;
                    if(f[v][y]==0){
                        f[v][y]=1;q.push((node){v,y});
                    }
                }
            }
        }
    }
    int main()
    {
        freopen("travel.in","r",stdin);
        freopen("travel.out","w",stdout);
        cin>>cas;
        while(cas--){
            cin>>n>>m>>T;
            ll u,v,t;Cl();
            for(ll i=1;i<=m;i++){
                cin>>u>>v>>t;
                u++;v++;Add(u,v,t);Add(v,u,t);
                if(u==1||v==1)mx=min(mx,t*2);
            }
            if(mx==0x7fffffff){
                printf("Impossible
    ");continue;
            } 
            SPFA();
            if(dis[n][T%mx]<=T)printf("Possible
    ");
            else printf("Impossible
    ");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Go的50坑:新Golang开发者要注意的陷阱、技巧和常见错误[2]
    Go的50坑:新Golang开发者要注意的陷阱、技巧和常见错误[1]
    进程和线程
    Linux 技巧:让进程在后台可靠运行的几种方法
    Linux 网络命令必知必会之 tcpdump,一份完整的抓包指南请查收!
    这些好用的 Chrome 插件,提升你的工作效率
    golang学习笔记-go mod的使用
    性能监控和分析工具---nmon
    Jenkins
    程序员画图工具总结
  • 原文地址:https://www.cnblogs.com/yanlifneg/p/6063210.html
Copyright © 2020-2023  润新知