zoukankan      html  css  js  c++  java
  • 2020.10.22 模拟赛题解

    CSDN同步

    注:所有题目并非作者版权,也并非本人原创。本人只是为了方便大家调试,将校内的题面与数据利用平台做成题目,并对题面进行部分美化。特此说明。

    房间开灯(( ext{lightson})

    简要题意:略。

    彩蛋:我们老师说这道题可以做 (TG space T1),爷笑了。

    做法很显然是宽搜,但是有细节。因为有回头路。

    比方说你 ((1,1) ightarrow (1,2) ightarrow (1,3)),发现 ((1,3))((2,1)) 的灯开了,这时候你就要倒回去才能走到 ((2,1)),进行下一步操作。

    那你可能会说,好,我把开灯的位置都走一遍呢?也不对。如果你开灯的房间是你走不到的呢?这怎么办?很显然我们需要一个数组来记录 当前房间的门有没有被打开。被打开的话,之后被开灯就可以直接入队搜索;未被打开的话,之后被开灯也无益。最后统计答案。

    这样思路很明显了,但是代码有细节。

    时间复杂度:(mathcal{O}(n^2 + m)).(数据出水了)

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=1e2+1;
    
    inline int read(){char ch=getchar(); int f=1; while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
    	int x=0; while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*f;}
    
    inline void write(int x) {
    	if(x<0) {putchar('-');write(-x);return;}
    	if(x<10) {putchar(char(x%10+'0'));return;}
    	write(x/10);putchar(char(x%10+'0'));
    }
    
    const int dx[4]={-1,0,0,1};
    const int dy[4]={0,-1,1,0};
    
    int n,m,ans=0;
    vector<pair<int,int> > a[N][N];
    bool h[N][N],lit[N][N],door[N][N];
    // h 记录队列是否搜索过这个元素
    // lit 记录该房间的灯是否打开
    // door 记录该房间的门是否打开
    queue<pair<int,int> > q;
    
    int main() {
    //	freopen("lightson.in","r",stdin);
    //	freopen("lightson.out","w",stdout);
    	n=read(),m=read();
    	while(m--) {
    		int x=read(),y=read(),u=read(),v=read();
    		a[x][y].push_back(make_pair(u,v));
    	} q.push(make_pair(1,1)); lit[1][1]=1; door[1][1]=1;
    	while(!q.empty()) {
    		int x=q.front().first,y=q.front().second;
    		q.pop(); if(h[x][y]) continue; h[x][y]=1;
    		for(register int i=0;i<a[x][y].size();i++) {
    			int nx=a[x][y][i].first,ny=a[x][y][i].second;
    			lit[nx][ny]=1;
    			if(door[nx][ny] && !h[nx][ny]) q.push(make_pair(nx,ny));
    		}
    		for(register int i=0;i<4;i++) {
    			int nx=x+dx[i],ny=y+dy[i];
    			if(nx<1 || ny<1 || nx>n || ny>n || h[nx][ny]) continue;
    			door[nx][ny]=1; if(lit[nx][ny]) q.push(make_pair(nx,ny));
    		}
    	}
    	for(register int i=1;i<=n;i++) 
    	for(register int j=1;j<=n;j++) if(lit[i][j]) ans++/*,printf("%d %d
    ",i,j)*/;
    	printf("%d
    ",ans);
    	return 0;
    }
    
    

    水果盛宴(feast)

    简要题意:略。

    显然,(T leq 5 imes 10^6) 是个线性做法,如何动态规划?

    一种思路是考虑 (f_i) 表示 (leq i) 的最大饱腹值(不喝水),最后考虑喝水的情况。则:

    (f_i = max(f_{i-A} + A , f_{i-B} + B))

    如何考虑喝水?则 (f_i)(f_{i div 2}) 如何建立联系?只能喝一次水,难以解决问题。

    这样我们考虑记忆化搜索,试图改变这个策略。现在我们的状态多一维,由于搜索的灵活性,我们的状态转移灵活了 (114514) 倍。

    当前 (dfs(x,f)) 表示当前的饱腹值为 (x),是否喝过水((f=1) 喝过,(f=0) 未喝过),可以轻松转移。

    注:这里有个坑。就是饱腹值 (x) 为奇数的时候也可以喝水,(x) 变为原来的 (lfloor frac{x}{2} floor),下取整。原题题意不明确,导致本人出错,特此说明,题面中也有标注。

    另外有个技巧:可以不必开 (f[1 - 5 imes 10^6][2]) 的数组,一维哈希即可解决问题。答案的记录每次打擂即可解决!

    时间复杂度:(mathcal{O}(T)).

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=5e6+1;
    
    inline int read(){char ch=getchar(); int f=1; while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
    	int x=0; while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*f;}
    
    inline void write(int x) {
    	if(x<0) {putchar('-');write(-x);return;}
    	if(x<10) {putchar(char(x%10+'0'));return;}
    	write(x/10);putchar(char(x%10+'0'));
    }
    
    int T,A,B,ans;
    bool h[N];
    
    inline void dfs(register int x,bool f) {
    	if(h[x]) return; ans=max(ans,x);
    	h[x]=1;
    	if(!f/* && !(x&1)*/) dfs(x>>1,1); // 喝一口水
    	if(x+A<=T) dfs(x+A,f);            // 拿一个 A
    	if(x+B<=T) dfs(x+B,f);            // 拿一个 B
    }
    
    int main() {
    //	freopen("feast.in","r",stdin);
    //	freopen("feast.out","w",stdout);
    	T=read(); A=read(); B=read();
    	dfs(0,0); printf("%d
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    ecshop 整合 kindedotor
    css 一些小笔记
    linux 使用 随记录
    GIPZ 压缩
    js 代码 随记
    map和list循环遍历
    向数据库批量处理事件
    链表和数组的优劣比较
    内存对齐 和 sizeof小结
    C++的默认构造函数与构造函数
  • 原文地址:https://www.cnblogs.com/bifanwen/p/13861303.html
Copyright © 2011-2022 走看看