• NOIP模拟 6.26


    T1 子矩阵

    题目描述

    A有一个N×M的矩阵,矩阵中1~N*M(N*M)个整数均出现过一次。现在小A在这个矩阵内选择一个子矩阵,其权值等于这个子矩阵中的所有数的最小值。小A想知道,如果他选择的子矩阵的权值为i(1<=i<=N×M),那么他选择的子矩阵可能有多少种?小A希望知道所有可能的i值对应的结果,但是这些结果太多了,他算不了,因此他向你求助。

    输入格式:

    第一行,两个整数N, M

    接下来的N行,每行M个整数,表示矩阵中的元素。

    输出格式:

    N×M行,每行一个整数,其中第i行的整数表示如果小A选择的子矩阵权值为i,他选择的子矩阵的种类数。

    输入样例#1:

    2 3

    2 5 1

    6 3 4

    输出样例#1:

    6

    4

    5

    1

    1

    1

     

     

    题解:

    部分枚举,扫描列的典型模型

    枚举两个行数i,j(规定i <= j),寻找[i,j]行内的矩形

    递推可得[i,j]行内每一列的最小值

    维护单调递增的栈,计算L[k](在[i,j]行内选择第k列,则向左最远能够选到L[k]列),R[i](在[i,j]行内选择第k列,则向右最远能够选到R[k]列)

    乘法原理得到左右行数在[i,j]内的、包含第k列的子矩阵

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    inline void read(int &x){x = 0;char ch = getchar();char c = ch;while(ch > '9' || ch < '0')c = ch, ch = getchar();while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0',ch = getchar();if(c == '-')x = -x;}
    inline void swap(int &a, int &b){int tmp = a;a = b;b = tmp;}
    inline int max(int a, int b){return a > b ? a : b;}
    inline int min(int a, int b){return a < b ? a : b;}
    
    const int INF = 0x3f3f3f3f;
    const int MAXN = 5000 + 10;
    const int MAXM = 100000;
    
    int n,m,num[MAXN][MAXN];
    int stack[MAXM], top;
    int mi[MAXM];
    int L[MAXM],R[MAXM];
    int ans[MAXM];
    
    int main()
    {
    	read(n);read(m);
    	for(int i = 1;i <= n;++ i)
    		for(int j = 1;j <= m;++ j)
    			read(num[i][j]);
    	//枚举上面的行i
    	for(register int i = 1;i <= n;++ i)
    	{
    		//注意清为最大值 
    		memset(mi, 0x3f, sizeof(mi));
    		
    		//枚举i以下的行j 
    		for(register int j = i;j <= n;++ j)
    		{
    			 //求得行[i,j]范围内的每一列的最小值 
    			for(register int k = 1;k <= m;++ k)
    				mi[k] = min(mi[k], num[j][k]);
    				
    				
    			//正向扫描求R,维护一个递增(或相等)单调栈
    			for(register int k = 1;k <= m;++ k)
    			{
    				while(top && mi[k] < mi[stack[top]])
    				{
    					R[stack[top]] = k - 1;
    					-- top;
    				}
    				stack[++top] = k;
    			}
    			while(top)
    			{
    				R[stack[top]] = m;
    				-- top;
    			}
    			
    			//反向扫描求L,维护一个递增(或相等)单调栈
    			 for(int k = m;k >= 1;k --)
    			 {
    			 	while(top && mi[k] < mi[stack[top]])
    			 	{
    			 		L[stack[top]] = k + 1;
    					-- top;
    			 	}
    			 	stack[++top] = k;
    			 }
    			 while(top)
    			 {
    			 	L[stack[top]] = 1;
    			 	-- top;
    			 }
    			 
    			 //扫描列,累加答案 
    			 for(register int k = 1;k <= m;k ++)
    			 {
    			 	ans[mi[k]] += (k - L[k] + 1) * (R[k] - k + 1);
    			 } 
    		}
    	}
    	register int tmp = n * m;
    	for(register int i = 1;i <= tmp;++ i)
    	{
    		printf("%d
    ", ans[i]);	
    	}
    	return 0;
    }
    

    T2 序列操作

    题目描述

    B有一个整数序列a[1..N],初始时序列中所有元素均为0。他会在序列上进行下面两种操作,操作共M个:

    1A l r x:将a[l..r]均加上x

    2Q l r:询问a[l..r]中的最大值。

    输入格式:

    第一行,两个整数N, M

    接下来的M行,每行一个操作。

    输出格式:

    设询问操作有T个,则输出T行,每行一个整数,表示询问操作对应的答案。

    输入样例#1:

    5 5

    A 1 4 1

    A 2 5 2

    Q 1 4

    A 3 4 -2

    Q 3 5

    输出样例#1:

    3

    2

     

    题解:线段树裸题

     

    代码:

     

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <string>
    #include <algorithm>
    inline void read(int &x){x = 0;char ch = getchar();char c = ch;while(ch > '9' || ch < '0')c = ch, ch = getchar();while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0',ch = getchar();if(c == '-')x = -x;}
    inline void swap(int &a, int &b){int tmp = a;a = b;b = tmp;}
    inline int max(int a, int b){return a > b ? a : b;}
    inline int min(int a, int b){return a < b ? a : b;}
    
    const int INF = 0x3f3f3f3f; 
    const int MAXN = 100000 + 10;
    const int MAXM = 100000 + 10;
    
    int sgtmax[MAXN];
    int sgtlazy[MAXN];
    int n,m;
    
    inline void putdown(int& o, int& l, int& r)
    {
    	sgtmax[o << 1] += sgtlazy[o];
    	sgtlazy[o << 1] += sgtlazy[o];
    	sgtlazy[o << 1 | 1] += sgtlazy[o];
    	sgtmax[o << 1 | 1] += sgtlazy[o];
    	sgtlazy[o] = 0;
    }
    
    void modify(int ll, int rr, int k, int o = 1, int l = 1, int r = n)
    {
    	if(ll <= l && rr >= r)
    	{
    		sgtmax[o] += k;
    		sgtlazy[o] += k;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	if(sgtlazy[o])putdown(o, l, r);
    	if(mid >= ll)modify(ll, rr, k, o << 1, l, mid);
    	if(mid < rr)modify(ll, rr, k, o << 1 | 1, mid + 1, r);
    	sgtmax[o] = max(sgtmax[o << 1], sgtmax[o << 1 | 1]);
    }
    
    int ask(int ll, int rr, int o = 1, int l = 1, int r = n)
    {
    	if(ll <= l && rr >= r)
    	{
    		return sgtmax[o];
    	}
    	int mid = (r + l) >> 1;
    	if(sgtlazy[o])putdown(o, l, r);
    	int ans = -INF;
    	if(mid >= ll)ans = max(ans, ask(ll, rr, o << 1, l, mid));
    	if(mid < rr)ans = max(ans, ask(ll, rr, o << 1 | 1, mid + 1, r));
    	return ans;
    }
    
    
    int main()
    {
    	read(n);read(m);
    	register int i,tmp1,tmp2,tmp3;
    	register char c;
    	for(i = 1;i <= m;i ++)
    	{
    		c = getchar();
    		while(c != 'A' && c != 'Q')c = getchar();
    		if(c == 'A')
    		{
    			read(tmp1);read(tmp2);read(tmp3);
    			modify(tmp1, tmp2, tmp3);
    		}
    		else
    		{
    			read(tmp1);read(tmp2);
    			printf("%d
    ", ask(tmp1, tmp2));
    		}
    	}
    	return 0;
    }
    

     

    T3 议案决定

    题目描述

    C在玩一个游戏,在游戏中他扮演国王的角色。国王手下有M个大臣,他们有一天对国王要处理的N件事务进行投票。 每个大臣可以对两件事务进行投票(赞成或反对),格式如下:x c_x y c_yx, y为整数,c_x, c_y“Y”(表示赞成)或“N”(表示反对)(不含双引号),表示这个大臣对事务x的态度为c_x,对事务y的态度为c_y)。这些大臣非常难以对付,如果国王的决定和某个大臣的两个意见都不同,那么这个大臣就会离开国王。小C认为不能让任何一个大臣离开国王,否则国王就无法正常地处理自己的事务。 请你帮助小C做个决定。

    输入格式:

    第一行,两个整数N, M

    接下来的M行,每行表示一个大臣的投票。

    输出格式:                      

    如果小C无论如何都只能让至少一个大臣离开国王,则输出“IMPOSSIBLE”(不含双引号),否则输出一个长度为N的字符串 ,如果第i件事务必须赞成,则第i个字符为“Y”;如果第i件事务必须反对,则第i个字符为“N”,否则第i个字符为“?”

    输入样例#1:

    3 4

    1 Y 2 N

    1 N 2 N

    1 Y 2 Y 

    输出样例#1:

    YN?

     

    题解:

    经典2-SAT问题

    点u->v代表u发生则v必然发生

    每一个条件可以拆为这样的两个条件

    如1 Y 2 N  对应的是  1N->2N   2Y->1Y

    我们把1Y  1N称为对立节点

    符合条件的情况是,从节点i出发找一条路径,路径上不会遇到i的对立节点。

     

     

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    
    const int MAXN = 80000 + 10;
    
    inline void read(int &x){x = 0;char ch = getchar();char c = ch;while(ch > '9' || ch < '0')c = ch, ch = getchar();while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar();if(c == '-')x = -x;}
    inline void read(char& x){x = 0;while(x != 'Y' && x != 'N')x = getchar();}
    
    struct Edge{int u,v,next;}edge[MAXN << 1];
    int head[MAXN << 1],cnt;
    void insert(int a, int b){edge[++cnt] = Edge{a,b,head[a]};head[a] = cnt;}
    
    int n,m;
    
    int ans[MAXN];
    
    //Y:ou shu N:ji shu 
    
    int match[MAXN << 1];
    
    int dfs(int u)
    {
    	for(int pos = head[u];pos;pos = edge[pos].next)
    	{
    		int v = edge[pos].v;
    		if(!v || v == 1)continue;
    		if(v & 1)
    		{
    			if(match[v - 1])return 0;
    			if(match[v])continue;	
    			match[v] = 1;
    			int tmp = dfs(v);
    			if(!tmp) return 0;
    		}
    		else
    		{
    			if(match[v | 1])return 0;
    			if(match[v])continue;
    			match[v] = 1;
    			int tmp = dfs(v);
    			if(!tmp)return 0;
    		}
    	}
    	return 1;
    }
    
    inline int check(int i)
    {
    	memset(match, 0, sizeof(match));
    	match[i] = 1;
    	return dfs(i);
    }
    
    const char a[3] = {'?', 'Y', 'N'};
    
    int main()
    {
    	read(n);read(m);
    	register char c1,c2;register int tmp1, tmp2;
    	register int i;
    	for(i = 1;i <= m;++ i)
    	{
    		read(tmp1);read(c1);read(tmp2);read(c2);
    		if(c1 == 'Y' && c2 == 'N')
    		{
    			insert(tmp1 << 1 | 1, tmp2 << 1 | 1);
    			insert(tmp2 << 1, tmp1 << 1);
    		}
    		else if(c1 == 'Y' && c2 == 'Y')
    		{
    			insert(tmp2 << 1 | 1, tmp1 << 1);
    			insert(tmp1 << 1 | 1, tmp2 << 1);
    		}
    		else if(c1 == 'N' && c2 == 'N')
    		{
    			insert(tmp2 << 1, tmp1 << 1 | 1);
    			insert(tmp1 << 1, tmp2 << 1 | 1);
    		}
    		else if(c1 == 'N' && c2 == 'Y')
    		{
    			insert(tmp2 << 1 | 1, tmp1 << 1 | 1);
    			insert(tmp1 << 1, tmp2 << 1);
    		}
    	}
    	
    	for(i = 1;i <= n;i ++)
    	{
    		tmp1 = check(i << 1);
    		tmp2 = check(i << 1 | 1);
    		if(tmp1 && tmp2)ans[i] = 0;
    		else if(tmp1)ans[i] = 1;
    		else if(tmp2)ans[i] = 2;
    		else
    		{
    			printf("IMPOSSIBLE");
    			return 0;
    		}
    	}
    	
    	for(int i = 1;i <= n;i ++)
    	{
    		printf("%c", a[ans[i]]);
    	}
    	return 0;
    }
    

     

     

     

  • 相关阅读:
    nginx优化:使用expires在浏览器端缓存静态文件
    nginx优化:worker_processes/worker_connections/worker_rlimit_nofile
    centos8平台使用ulimit做系统资源限制
    centos8平台nginx服务配置打开文件限制max open files limits
    nginx安全:配置allow/deny控制ip访问(ngx_http_access_module)
    python 菜鸟入门
    正则表达式预查询
    selenium 关键字驱动部分设计思路
    Idea安装Python插件并配置Python SDK
    ORACLE LOG的管理
  • 原文地址:https://www.cnblogs.com/huibixiaoxing/p/7081926.html
Copyright © 2020-2023  润新知