首页 > 其他 > 详细

2020.11.2校测解题报告

时间:2020-11-02 22:28:55      阅读:34      评论:0      收藏:0      [点我收藏+]

2020.11.2校测 解题报告

得分情况:

  • T1 期望得分:100 实际得分:100
  • T2 期望得分:100 实际得分:0
  • T3 期望得分:0 实际得分:0

T1

  • 思路

    不妨设 a < b

    假设答案为 x

    ? x≡ma (mod b)(1 ≤ m ≤ b?1)

    ? x=ma+nb ( 1 ≤ m ≤ b?1)

    显然当 n ≥ 0 时 x 可以用 a , b 表示出来,不合题意。

    因此当 n = -1 时 x 取得最大值,此时 x = ma - b 。

    显然当 m取得最大值 b - 1 时 x 最大,此时 x = (b - 1)a - b = ab - a - b

    因此 a, b 所表示不出的最大的数是 ab - a - b

  • 代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue> 
    #define ll long long
    #define InF 2147483647
    
    using namespace std;
    /*====================================快读*/
    int read()
    {
        int x=0,f=1;
    	char c=getchar();
        while(c<‘0‘||c>‘9‘)
    	{
    		if(c==‘-‘) 
    			f=-1;
    		c=getchar();
    	}
        while(c>=‘0‘&&c<=‘9‘)
        { 
    		x=(x<<3)+(x<<1)+(c^48); 
    		c=getchar();
    	}
        return x*f;
    } 
    /*======================================定义变量*/
    ll a,b;
    /*====================================自定义函数*/
    
    /*========================================主程序*/
    int main()
    {
    //	freopen("math.in","r",stdin);
    //	freopen("math.out","w",stdout);
    	a=read();
    	b=read();
    	printf("%ld",a*b-a-b);
    	return 0;
    }
    
  • Tips

    1. 不开 long long 见祖宗。

    2. 输出格式应与定义格式保持一致。


T2

  • 思路

    1. 这不就是个大模拟吗??

      模拟好啊,模拟无脑,我最会打模拟了/得意。

      最后得分:\(0 pts\)……

    2. ERR跳出后如何读下一组数据?

    3. 一直读,直到含有大写字母O

    4. 若遇到初值大于末值应如何处理?

    5. 标记一下,后面的只判断ERR

    6. 退出循环时更改什么判断什么取消什么?

    7. 循环数取max,若之前标记过,取消即可,同时变量也要取消

  • 代码

    #include<bits/stdc++.h>
    using namespace std;
    string a,b;     //a,b循环使用
    int c,d,e,f[27],g[27],h,k,l[100],m,n,T;
    //c是有几个句子,d是题目给的复杂度是多少
    //e是当前在几重循环,f[]是判断变量是否使用过
    //g[]是存下每个循环的变量,h是当前复杂度是多少(与e不同)
    //k是判断下面程序是否进行,l[]是存下哪几个循环加了复杂度
    //m是当前最大复杂度,n是存下k=1时的循环数
    //o是数据组数
    void csh()
    {
    	c=0;
    	d=0;
    	m=0;
    	n=0;
    	e=0;
    	h=0;
    	k=0;    //初始化,剩余数据组数-1
    	memset(f,0,sizeof(f));
    	memset(l,0,sizeof(l));   //初始化
    }
    int main()
    {
    	cin>>T;    //读入数据组数
    	while(T--)
    	{
    		while(1)
    		{
    			a=b;
    			cin>>b;
    			if(b[0]==‘O‘)
    				break;
    		}     //读入,当b[0]=‘O‘时停下,保证ERR时下一个继续运行
    		for(int i=0; i<a.length(); i++) c=c*10+a[i]-‘0‘; //取出题目给的句子数量
    		for(int i=4; i<b.length()-1; i++) d=d*10+b[i]-‘0‘; //取出题目给的时间复杂度 O(1)不影响
    		while(c>0) 
            {
    			c--;
    			cin>>a;   //读入F 或 E ,句子数-1
    			if(a[0]==‘F‘) 
                { //如果是F
    				e++;
    				cin>>a;   //当前循环数+1,读入变量
    				if(f[a[0]-96]) 
                        e=-1;    //如果被用过,标记ERR
    				else 
                    {
                        f[a[0]-96]=1;
                        g[e]=a[0]-96;
                    }    //没用过就标记用过,并存起来
    				cin>>a>>b;      //读入变量初值和末值
    				if(a[0]!=‘n‘&&b[0]==‘n‘&&k==0) 
                    {
                        h++;
                        l[e]=1;
                    }//如果a是数字,b是n,而且可以运行,那么当前复杂度+1,记下循环数
    				else if(((a.length()==b.length()&&a>b)||(a.length()>b.length())||(a[0]==‘n‘&&b[0]!=‘n‘))&&k==0)
                    {
                        k=1;n=e;
                    }
    				//如果a>b(n 4,45 12,24 9),而且可以运行,那么标记下面的都不能运行,记下当前循环
    				//像5 8,76 78, n n 之类的不影响,不需要处理
    			}
                else 
                {
    				//如果是E
    				m=m>h ? m : h;
    				f[g[e]]=0;     //将最大复杂度更改 ,变量标记没用过
    				if(l[e]==1) 
                    {
                        h--;
                        l[e]=0;
                    }  //如果当前循环加了复杂度,当前复杂度-1,标记清空
    				e--;    //当前循环数-1
    				if(n>0&&e<n) 
                    {
                        k=0;
                        n=0;
                    }   //如果跳出了n标记的那个循环,那么接下来的循环可以运行,标记清空
    			}
    			if(e==-1) 
                {
                    printf("ERR\n");
                    c=-1;
                }
                       //如果e<0(变量用过或者E过多),那么输出ERR,跳出循环
    		}
    		if(e>0) 
                printf("ERR\n");    //如果e>0(F过量),那么输出ERR,跳出循环
    		if(e==0&&m==d) 
                printf("Yes\n");   //如果F,E相同而且最大复杂度等于题目给的复杂度,输出Yes
    		if(e==0&&m!=d) 
                printf("No\n");    //如果F,E相同而且最大复杂度不等于题目给的复杂度,输出No
    	}
    	return 0;
    }  
    
  • Tips:

    1. 大模拟题注意细节
    2. 大括号可以辅助理清思路

T3

  • 思路

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

    2. 下面有dis[i]表示i号点到n号点的最短路径长度。

      \(f[i][j]\)表示从i号点走到n号点,走了j的多余路径的方案数。就有如下转移方程式:

      \(f[i][j]\)=\(\sum\limits_{i,v之间有边}\)\(f[v][j-(dis[v]+w-dis[i])]\)

      记忆化搜索即可。

      注意到如果出现了无数条路径,肯定出现了0环。也就是某一个状态被访问了两次。记忆化搜索的过程中标记一下即可。

  • 代码

    #include<cstdio>
    #include<iostream>
    #include<ctime>
    #include<queue>
    #include<cstring>
    #include<string>
    using namespace std;
    typedef long long ll;
    const int N = 200010;
    ll read() {
    	ll x = 0,f = 1;char c = getchar();
    	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 node {
    	int v,nxt,w;
    }e[N << 1],E[N << 1];
    int head[N],ejs;
    void add(int u,int v,int w) {
    	e[++ejs].v = v;e[ejs].nxt = head[u];head[u] = ejs;e[ejs].w = w;
    }
    int head2[N],ejs2;
    void add2(int u,int v,int w) {
    	E[++ejs2].v = v;E[ejs2].w = w;E[ejs2].nxt = head2[u];head2[u] = ejs2;
    }
    queue<int>q;
    int n,m,K,mod,dis[N],vis[N];
    void spfa(int U) {
    	memset(dis,0x3f,sizeof(dis));
    	memset(vis,0,sizeof(vis));
    	dis[U] = 0;
    	q.push(U);
    	while(!q.empty()) {
    		int u = q.front();q.pop();vis[u] = 0;
    		for(int i = head2[u];i;i = E[i].nxt) {
    			int v = E[i].v;
    			if(dis[v] > dis[u] + E[i].w) {
    				dis[v] = dis[u] + E[i].w;
    				if(!vis[v]) {
    					vis[v] = 1;q.push(v);
    				}
    			}
    		}
    	}
    }
    int bz[N][60],f[N][60];
    int dfs(int u,int x) {
    	if(bz[u][x] == 2) return f[u][x];
    	if(bz[u][x] == 1) return -1;
    	bz[u][x] = 1;
    	for(int i = head[u];i;i = e[i].nxt) {
    		int v = e[i].v;
    		int w = x - (dis[v] + e[i].w - dis[u]);
    		if(w < 0 || w > K) continue;
    		int k = dfs(v,w);
    		if(k == -1) return -1;
    		f[u][x] += k;
    		f[u][x] %= mod;
    	}
    	bz[u][x] = 2;
    	return f[u][x];
    } 
    int main() {
    	int T = read();
    	while(T--) {
    		memset(head,0,sizeof(head));
    		ejs2 = 0;
    		memset(head2,0,sizeof(head2));
    		ejs = 0;
    		n = read(),m = read(),K = read(),mod = read();
    		
    		memset(f,0,sizeof(f));
    		memset(bz,0,sizeof(bz));
    		
    		for(int i = 1;i <= m;++i) {
    			int u = read(),v = read(),w = read();
    			add(u,v,w);
    			add2(v,u,w);
    		}
    		
    		spfa(n);
    		
    		f[n][0] = 1;
    		int ans = 0;
    		for(int i = 0;i <= K;++i) {
    			int k = dfs(1,i);
    			if(k == -1) {
    				ans = -1;break;
    			}
    			ans += k;
    			ans %= mod;
    		}
    		printf("%d\n",ans);
    	}
    	
    		
    	return 0;
    }
    
  • Tips:

    其实这题 \(DJ+DFS\) 可以跑过 \(60pts\),但是遇到 \(0\) 环就无能为力了。

2020.11.2校测解题报告

原文:https://www.cnblogs.com/Frather/p/13916742.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!