zoukankan      html  css  js  c++  java
  • CodeForces 732D Exams

    /*
    
    这题的思路据是二分+贪心,二分枚举所有解,贪心判断能否考完 
    注意,这题自己写代码时,出了一个很隐蔽的bug,当时本来已经把变量 n、m 定义为全局变量了,但居然在main函数里又定义了一次,这就相当于屏蔽了全局变量,虽然输入是正确的,但是,在judge()函数判断能否考完的过程中,所用的n、m都是错的(因为此时真正的是作为局部变量出现的,但judge()函数种使用的为全局) 
    以及注意,一般情况下,是不建议定义全局变量的,这题其实不定义也未尝不可,只是judge()函数就要传递3个参数了 
    
      BTW,其实入门经典里有提到过,全局变量被屏蔽,可能会导致错误。我以为我还算是仔细,今天看来,其实我也还是很粗心的...
      
      最初写这题总结的时候,我还不会二分法,参考了blog:
      http://www.cnblogs.com/westwind1005/p/5976882.html
    */ 



    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e5 + 5;
    int a[N];
    int d[N];
    int pass[N];
    int n, m;
    int judge(int x)
    {
    	memset(pass, 0, sizeof(pass));
    	int pre = x - 1;
    	for (int i = x; i >= 1; i--) //从后往前遍历天数
    	{
    		pre = min(pre, i - 1); //不断更新为这门考试的准备时间,最多也只能是i - 1天的复习时间
    		if (d[i] && !pass[d[i]] && a[d[i]] <= pre)
    		{
    			pass[d[i]] = 1;
    			pre -= a[d[i]] + 1; //+1为下次考试所占的一天,若下次要考试,则下次的准备时间,除了要减去这次考试的准备时间,还要减去下次作为考试的那天
    		}
    	}
    	for (int i = 1; i <= m; i++)
    	if (!pass[i]) return 0;
    	return 1;
    }
    int main()
    {
    	while (cin >> n >> m)
    	{	
    		int ans = -1;
    		for (int i = 1; i <= n; i++) cin >> d[i];
    		for (int i = 1; i <= m; i++) cin >> a[i];
    		
    		int l = 1,r = n;
    		while (l <= r)
    		{
    			int mid = (l + r) >> 1;
    			if (judge(mid))
    			{
    				ans = mid; r = mid - 1;
    			}
    			else
    			{
    				l = mid + 1;
    			}
    		}
    		cout << ans << endl;
    	}		
    	return 0;
    }


    /*
      法二
      后来在另外一个blog上,看到judge函数的另外一种写法,这种写法比较容易理解,所以我也自己写了一次
      思路来自: http://blog.csdn.net/qq_34374664/article/details/52853212
      BTW,上面那篇博客里,博主对这题的解释十分详细,比我自己的代码的解释详细多了...
    */


    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e5 + 5;
    int a[N];
    int d[N];
    int pass[N];
    int n, m;
    int judge(int x)
    {
    	memset(pass, 0, sizeof(pass));
    	int sum = 0, cnt = 0; // cnt 用来记录通过的科目数,sum用来目前还需要在前面找多少天复习 
    	for (int i = x; i >= 1; i--) //从后往前遍历天数
    	{
    		if (d[i] && !pass[d[i]]) // 如果可以考试且这门课没考,则考 
    		{
    			pass[d[i]] = 1;
    			sum += a[d[i]];
    			cnt++;
    		}
    		else if (sum > 0) //如果还需要从前面抽出时间复习,那么就用这天复习,否则就当作休息;注意一定要当前需要前面sum天复习,sum才能自减,如果sum本来就为0,就不可减了,否则WA 
    		{
    			sum--;
    		} 
    	}
    	if (sum > 0|| cnt < m) return 0;
    	return 1;
    }
    int main()
    {
    	while (cin >> n >> m)
    	{	
    		int ans = -1;
    		for (int i = 1; i <= n; i++) cin >> d[i];
    		for (int i = 1; i <= m; i++) cin >> a[i];
    		
    		int l = 1,r = n;
    		while (l <= r)
    		{
    			int mid = (l + r) >> 1;
    			if (judge(mid))
    			{
    				ans = mid; r = mid - 1;
    			}
    			else
    			{
    				l = mid + 1;
    			}
    		}
    		cout << ans << endl;
    	}		
    	return 0;
    }


    /*
      法三:
      法三利用了栈,我觉得是三种写法总最容易懂的,但似乎也就没有前两种简洁了。
      这三种方法,本质上是一样的,只是写法的区别,思路上差异不大
    */
    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e5 + 5;
    int a[N];
    int pass[N];
    int n, m;
    
    struct day
    {
    	int test, have; //变量分别表示:当天能考的科目,已为该科目准备了多久
    	day()
    	{
    		have = 0;
    	}
    }d[N];
    
    int judge(int x)
    {
    	int ans = 0; // 记录有几门科目考完 
    	memset(pass, 0, sizeof(pass));
    	stack<day> s; 
    	day now; // 当前天数 
    	for (int i = x; i >= 1; i--)
    	{
    		if (d[i].test && !pass[d[i].test]) //  从后往前遍历,如果某天有考试,且还没考,那就考这科 
    		{
    			pass[d[i].test] = 1;
    			s.push(d[i]);
    		}
    		else if ( !s.empty() ) // 否则,取出最近的一次(没准备好)的考试,这天用来准备 
    		{
    			now = s.top();
    			s.pop();
    			now.have++;
    			
    			if ( now.have == a[now.test] ) //如果需要的准备时间,全都准备好了,则真正出栈。否则,准备时间子增后,再次入栈
    			ans++;
    			else s.push(now);
    		}
    	}
    	if (ans == m) return 1;
    	return 0;
    }
    
    int main()
    {
    	while (cin >> n >> m)
    	{	
    		int ans = -1;
    		for (int i = 1; i <= n; i++) cin >> d[i].test;
    		for (int i = 1; i <= m; i++) cin >> a[i];
    		
    		int l = 1,r = n;
    		while (l <= r)
    		{
    			int mid = (l + r) >> 1;
    			if (judge(mid))
    			{
    				ans = mid; r = mid - 1;
    			}
    			else
    			{
    				l = mid + 1;
    			}
    		}
    		cout << ans << endl;
    	}		
    	return 0;
    }





  • 相关阅读:
    面试准备
    论文投稿Cover letter
    Pycharm 快捷键
    linux下常用命令:
    Qt中数据模块学习
    Qt 多线程和网络编程学习
    VS高效开发快捷键
    良好编码风格习惯整理
    Qt QAxObject操作excel文件过程总结(转):
    Qt开发中的实用笔记三--关于各种类的零碎知识点:
  • 原文地址:https://www.cnblogs.com/mofushaohua/p/7789505.html
Copyright © 2011-2022 走看看