zoukankan      html  css  js  c++  java
  • NOIP 2017 Day1 解题报告

    总分:100分

    T1,小凯的疑惑, 100分

    T2,时间复杂度,0分

    T3,逛公园,0分


    T1
    ###题意简化:
    给定两个互质的数字,输出最大不能表示的数;

    基础数论题目
    代码:

    #include<bits/stdc++.h>
    using namespace std;
    inline long long read()
    {
    
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    	return x*f;
    }
    int main()
    {
    	
    	long long a,b;
    	a=read(),b=read();
    	cout<<a*b-a-b;
    	return 0;
    }
    

    T2:

    解题思路:

    对于模拟题:学到了一点:模块化,尽量处理的时候分开,不然凑一起真炸的满天飞

    1.就是输入的问题,输入t组数据肯定没有什么问题

    2.输入循环体的时候,我在考试的时候选择了字符读入,然后我人傻了,不知道怎么做了,学长讲的那就是直接string code[105],然后就可以表示了,

    3.对于第一个板块,也就是我们首先要处理的东西,那就是字符串中的数字,(代码中就是calc--计算器),这个确有巧妙,当时我因为字符读入,直接减去'0';

    注:原来题目给定的时间复杂度一样这么求,只不过在前面进行稍微判别,函数名为 geto();

    4.对于第二个板块,在进行我们主体部分,进行大模拟,模拟首先就是我们要考虑我们碰上'F'之后的事情

    (1).我们肯定需要把这个循环的迭代器找出来也就是 code[i][2],我们直接以一个bool数组表示它是否已经用过了,如果用过,那么就是编译错误;

    (2).我们将循环变量压入栈中,会发现,和括号的匹配很像

    (3).我们用a,b取出i,j

    如果 b<a ,那么没有进入循环。用一个 flag 来保存最早的没有没有进入的 k。

    如果都进入了,则flag为-1。

    如果 a<=b ,代表进入循环,此时若 b-a>1000 并且 flag 为 -1 ,则本层循环对复杂度有贡献,执行 now++ 操作。

    同时我们用 ef[26] 保存 now++ 时 k的信息**(ef[k]=true)。(在k出栈时now - -,ef[k]=false)并更新res。(res=max(res,now))

    5.那碰上‘E’呢

    (1).首先我们看下栈,空,代表'F'已经没有了,但是‘E’还有,不匹配

    (2).计算一下时间复杂度

    (3).在最后的时候看一下‘F’有没有剩下;

    经过九九八十一难,肝出来了,就是全力的模拟每一种情况,需要大量的耐心和清晰的头脑(我感觉我脑袋已经炸了)

    #include<cstdio>
    #include<stack>
    #include<string>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxl=105;
    int t,l,w;
    string o;
    string code[maxl];
    int calc(int &x,string c) 
    {
        int res=0;
        int len=c.size();
        while(c[x]<'0' || c[x]>'9'&&x<c.size()) {
            if(c[x]=='n'){
                ++x;
                return 1000000;
            }
            ++x;
        }
        while(c[x]>='0' && c[x]<='9') {
            res*=10;res+=c[x]-'0';
            ++x;
        }
        return res;
    }
    
    int geto() {
        int res=0,x=3;
        int len=o.size();
        if(o[2]=='n') res=calc(x,o);
        else res=0;
        return res;
    }
    
    int check() {
        int res=0,now=0;
        int a,b,x;
        stack<int> s;
        int flag=-1;
        bool ins[26]={0};
        bool ef[26]={0};
        for(int i=1;i<=l;i++) {
            if(code[i][0]=='F') {
                int k=code[i][2]-'a';
                if(ins[k]) return -1;
                s.push(k);ins[k]=true;
                x=4;
                a=calc(x,code[i]);b=calc(x,code[i]);
                if(b-a>1000) 
    			{
                    if(flag==-1)
    				{	
                        now++;
                        res=max(res,now);
                        ef[k]=true;
                    }
                }
                if(a>b) {
                    if(flag==-1) flag=k;
                }
            }
            if(code[i][0]=='E') {
                if(s.empty()) return -1;
                int k=s.top();
                s.pop();ins[k]=false;
                if(flag==k) flag=-1;
                if(ef[k]) {
                    ef[k]=false;
                    now--;
                }
            }
        }
        if(s.size()) return -1;
        return res;
    }
    
    int main() {
        scanf("%d",&t);
        while(t--) {
            int ww;
            scanf("%d ",&l); getline(cin,o);
            w=geto();
            for(int i=1;i<=l;i++) getline(cin,code[i]);
            ww=check();
            if(ww==-1) printf("ERR
    ");
            else {
                if(ww==w) printf("Yes
    ");
                else printf("No
    ");
            }
        }
    }
    

    T3:

    题意简化:

    一个有向无重边自环图,设D为从1号点走到n号点的最短距离。问有多少条从1到n的路径长度不超过D+K。K为给定的值,且K≤50,如果有无数条,输出-1

    题意分析

    首先看一下,k的取值,k≤50,就很容易想到DP,所以我们考虑一下,题目到底怎么DP

    1. 对于正常的图来说,它怎么也不可能有无穷条最短路(我们假设k=0的时候),那么也就只有有0环的时候才会出现这种情况,

    2.那么我们设一个二维数组 lh[u][x](轮回),表示 节点 U比最短路多出 x 的距离

    注:除了0环,不可能相等,相等的时候那就是说明我们在上一个节点走到这的时候返回这个点,节省复杂度

    3.然后我们就去寻找比最短路小 k的价值的答案(也就是边数)

    4.那么我们也可以设一个二维数组 f[u][x]表示节点 i到 n走了x的多余价值,

    5.然后就A掉了

      然后发现不会:
      那就暴力一下,数据很良心,给了k=0的情况,那就十分类似于[路径统计](https://www.luogu.com.cn/problem/P1608)。
      之后我们就开始正解了
    

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #define inf 0x3f
    using namespace std;
    const int maxn=1e5+10;
    struct node
    {
       int nxt, to,weath; 
    };
    node edge1[maxn<<1],edge2[maxn<<1];
    int head1[maxn<<1],head2[maxn<<1];
    int number_edge1,number_edge2;
    int n,m,k,p;
    //===============正反建图=================
    void add1(int from,int to,int weath)
    {
       number_edge1++;
       edge1[number_edge1].nxt=head1[from];
       edge1[number_edge1].to=to;
       edge1[number_edge1].weath=weath;
       head1[from]=number_edge1;
    }
    void add2(int from,int to,int weath)
    {
       number_edge2++;
       edge2[number_edge2].nxt=head2[from];
       edge2[number_edge2].to=to;
       edge2[number_edge2].weath=weath;
       head2[from]=number_edge2;
    }
    
    inline int read()
    {
       int x=0,f=1;char ch=getchar();
       while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
       while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
       return x*f;
    }
    //=======标准spfa========= 
    int dis[maxn],vis[maxn];
    queue<int> q;
    void spfa(int x)//标准spfa 
    {
       memset(dis,0x3f,sizeof(dis));
       memset(vis,0,sizeof(vis));
       dis[x]=0;
       //vis[x]=1;
       q.push(x);
       while(!q.empty())
       {
       	int u=q.front();
       	q.pop();
       	vis[u]=0;
       	for(int i=head2[u];i;i=edge2[i].nxt)
       	{
       		int v=edge2[i].to;
       		if(dis[v]>dis[u]+edge2[i].weath)
       		{
       			dis[v]=dis[u]+edge2[i].weath;
       			if(!vis[v])
       			{	
       				q.push(v);
       				vis[v]=1;
       			}
       		}
       	}
       }
    }
    //出现了无穷条,意味着出现了0环,那么标记一下,用的数组 lh(轮回) 
    int lh[maxn<<1][60],f[maxn<<1][60];
    //lh的右数组为什么开60,因为出现0环,在这个环上,无论那一个点,哪一种情况都将是 j的距离 
    //f[i][j]表示 从i号点到 n号点走了 j的多余路径 
    //=================寻找路径============== 
    int dfs(int u,int x)
    {
       if(lh[u][x]==2) return f[u][x];//从别的点出发到达了这个点,
       if(lh[u][x]==1) return -1;
       lh[u][x]=1;
       for(int i=head1[u];i;i=edge1[i].nxt)
       {
       	int v=edge1[i].to;
       	int w=x-(dis[v]+edge1[i].weath-dis[u]);
       	if(w<0 || w>k) continue;
       	int val=dfs(v,w);
       	if(val==-1) return -1;//有0环 
       	f[u][x]+=val;
       	f[u][x]%=p;
       } 
       lh[u][x]=2;
       return f[u][x]; 
    } 
    int main()
    {
       int t=read();
       
       while(t--)
       {
       	memset(head1,0,sizeof(head1));
       	number_edge1=0; 
       	
       	memset(head2,0,sizeof(head2));
       	number_edge2=0;
       	
       	memset(lh,0,sizeof(lh));
       	memset(f,0,sizeof(f));
       	
       	n=read(),m=read(),k=read(),p=read();
       	for(int i=1;i<=m;i++)
       	{
       		int u=read(),v=read(),w=read();
       		add1(u,v,w);
       		add2(v,u,w);
       	}
       	spfa(n);
       	
       	f[n][0]=1;
       	
       	int ans=0;
       	
       	for(int i=0;i<=k;i++)
       	{
       		int judge=dfs(1,i);
       		if(judge==-1)
       		{
       			ans=-1;				
       		}
       		else
       		{
       			ans+=judge;
       			ans%=p;
       		}	
       	}
       	printf("%d
    ",ans);
       }
       return 0;
    } 
    

    最后的总结:

    对于任何一道题来说,如果不会,先放一下,看一下后面的题是否可以做,拿部分分也是可以的,T2模拟模拟不出来却非要一直模拟,结果,T3就只有30分钟的时间,最后还编译出错了。

  • 相关阅读:
    数据结构--链表基础练习题
    LeetCode 10.28每日一题1207. 独一无二的出现次数【简单】
    数据结构--链表
    LeetCode 10.25每日一题845. 数组中的最长山脉【中等】
    LeetCode 10.22每日一题763. 划分字母区间【中等】
    解决map热点与uni-app中map标签冲突的问题。(Vue Render函数应用)
    【Codeforces 1329A】Dreamoon Likes Coloring
    【Codeforces Alpha Round #20 C】Dijkstra?
    【 Educational Codeforces Round 93 (Rated for Div. 2) D】Colored Rectangles
    【Codeforces Round #643 (Div. 2) C】Count Triangles
  • 原文地址:https://www.cnblogs.com/Zmonarch/p/13914864.html
Copyright © 2011-2022 走看看