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;
    }





  • 相关阅读:
    杭电 Problem
    杭电Problem 5053 the sum of cube 【数学公式】
    杭电 Problem 2089 不要62 【打表】
    杭电 Problem 4548 美素数【打表】
    杭电 Problem 2008 分拆素数和 【打表】
    杭电 Problem 1722 Cake 【gcd】
    杭电 Problem 2187 悼念512汶川大地震遇难同胞——老人是真饿了【贪心】
    杭电Problem 1872 稳定排序
    杭电 Problem 1753 大明A+B
    东北林业大 564 汉诺塔
  • 原文地址:https://www.cnblogs.com/mofushaohua/p/7789505.html
Copyright © 2011-2022 走看看