ZOJ 3955:Saddle Point(思维)

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3955

题意:给出一个n*m的矩阵,定义矩阵中的特殊点Aij当且仅当Aij是这一行最小的唯一元素,是这一列最大的唯一元素。删除一些行和列,剩下的元素构成的矩阵一共有(2^n-1)* (2^m-1)种,求这些矩阵的特殊点的个数。

思路:对于这种问题,可以考虑每一个点对答案的贡献。

其实就只是对于每一个点,找出在该行大于它的点的数目a,在该列大于它的点的数目b,然后该点对于答案的贡献就是2^a * 2^b,用快速幂处理一下。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define N 1010
 4 const int MOD = 1e9 + 7;
 5 typedef long long LL;
 6 LL mp[N][N], se[N], col[N][N], row[N][N];
 7 LL f_pow(LL a, LL b) {
 8     LL ans = 1;
 9     while(b) {
10         if(b & 1) ans = (ans % MOD * a) % MOD;
11         a = a * a % MOD;
12         b >>= 1;
13     }
14     return ans % MOD;
15 }
16 int main() {
17     int t; scanf("%d", &t);
18     while(t--) {
19         int n, m; scanf("%d%d", &n, &m);
20         for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) scanf("%lld", &mp[i][j]);
21         for(int i = 1; i <= n; i++) {
22             for(int j = 1; j <= m; j++) se[j] = mp[i][j];
23             sort(se + 1, se + m + 1);
24             for(int j = 1; j <= m; j++) row[i][j] = m - (upper_bound(se + 1, se + 1 + m, mp[i][j]) - se) + 1;
25         }
26         for(int i = 1; i <= m; i++) {
27             for(int j = 1; j <= n; j++) se[j] = -mp[j][i];
28             sort(se + 1, se + n + 1);
29             for(int j = 1; j <= n; j++) col[j][i] = n - (upper_bound(se + 1, se + 1 + n, -mp[j][i]) - se) + 1;
30         }
31         LL res = 0;
32         for(int i = 1; i <= n; i++) {
33             for(int j = 1; j <= m; j++) {
34 //                printf("%d - %d : %lld - %lld\n", i, j, row[i][j], col[i][j]);
35                 res = (res % MOD + f_pow(2LL, row[i][j]) * f_pow(2LL, col[i][j]) % MOD) % MOD;
36             }
37         }
38         printf("%lld\n", res % MOD);
39     }
40     return 0;
41 }
时间: 2024-10-05 05:05:43

ZOJ 3955:Saddle Point(思维)的相关文章

ZOJ 3955 Saddle Point

排序. 枚举每一个格子,计算这个格子在多少矩阵中是鞍点,只要计算这一行有多少数字比他大,这一列有多少数字比他小,方案数乘一下就是这个格子对答案做出的贡献. #include<bits/stdc++.h> using namespace std; int n,m; long long mod = 1e9+7; int a[1200][1200]; int num1[1200][1200]; int num2[1200][1200]; long long b[1200]; struct X { i

zoj 3672 思维题

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4915 真是老了,脑子不会动了,但是其实就算现在搜了题解A了,还是没总结出思维方式 三点: 1.segma(a[i]-b[i])必须是偶数,,因为其实每次操作都是相当于从segma(a[i]-b[i])里面减去2*delta 2.a[i]>=b[i] 题目说的很清楚,只能减去,所以这点必须满足 前两点都想到了,但是自己能举出反例,后来队友A掉了 3.max(a[i]-b[i])

ZOJ 3829 贪心 思维题

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3829 现场做这道题的时候,感觉是思维题,自己智商不够,不敢搞,想着队友智商好,他们搞吧,但是没出来这题...... 以后任何时候,都自信点....该想的还是好好自己想,这类题感觉就是先去找性质,然后一点点找规律,如果必要的话,自己提出一点猜想,然后如果自己举不出来反例,就暂时认为是正确的 下午搞了一下午,发现还是悲剧,晚上参考了两个题解 http://blog.csdn.

D - The Lucky Week ZOJ - 3939 (思维)

题目链接: D - The Lucky Week  ZOJ - 3939 题目大意:幸运的星期指,星期一为每个月的1 or 11 or 21号.给出第一个幸运星期的时间,问从当前的日起开始.第n个的日期. 具体思路:我们通过打表可以发现,每隔400年,当前的这一天的星期和400年后的是相同的.所以我们先求出一个400年有多少个幸运的天数(1600-1999),然后判断当前的年份如果以1600年开始的话,往后n个幸运日是多少,然后再做差以原来的起点输出就可以了. AC代码: 1 #include<

Welcome Party ZOJ - 4109 (思维+并查集)

题目链接: Welcome Party  ZOJ - 4109 题目大意:给你T组测试样例,然后n个人,m个关系,每一个关系包括两个人,这两个人为好朋友,然后问你怎么安排顺序,使得整个队伍的友情损失度最小(当一个人放置时,如果他的前面中没有他的朋友,那么整个队伍的朋友损失度就会加1) 具体思路:首先用并查集求出每一个联通块,然后用一个超级汇点连向这些连通块的根,然后优先队列+bfs求出字典序最小的正解就可以了. AC代码: 1 #include<bits/stdc++.h> 2 using n

ZOJ 2975 思维

题意 给出一个矩形 问在其中存在多少子矩形 其四个角上的字母是一样的 一开始暴力写了一发 先枚举行数 再枚举两个列数 再向下枚举行数 判断能否 没有意外的超时了 后来想了想 当我们已经确定两个列数的时候 向下寻找的时候 如果找到了tot条边与第一条边同字母 这些边可以组成(tot-1)*tot个矩形 使满足题意 为了避免重复寻找 需要一个map来记录 由于矩形的边最长100 我们存已经检索的字母*1000*1000+左列数*1000+右列数 #include<stdio.h> #include

ZOJ 3962:Seven Segment Display(思维)

https://vjudge.net/problem/ZOJ-3962 题意:有16种灯,每种灯的花费是灯管数目,代表0~F(十六进制),现在从x开始跳n-1秒,每一秒需要的花费是表示当前的数的花费之和,问n-1秒后这段时间的花费总共是多少.跳到FFFFFFFF之后会跳回00000000. 思路:怀疑人生的题目.如果从平时计算[L,R]的花费,就计算[0,R] - [0,L-1]这样的角度来看,就会好做很多.同样如果跳到1LL<<32之后回到0,也分段考虑.这样写一个函数就可以计算了. 考虑三

ZOJ 1654 Place the Robots建图思维(分块思想)+二分匹配

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=654 AC一百道水题,不如AC一道难题来的舒服. 题意:一个n*m地图.*代表草地,#代表墙,o代表空地,要再图中的o处放机器人,机器人能够攻击(上下左右)4个方向,攻击范围无限长,并且机器人不能相互攻击,草地不能放置机器人,且机器人的攻击能够穿过草地,可是机器人的攻击不能穿过墙,比方 "   *o#o  "这一行就能够放两个机器人," o*oo

ZOJ 3870 数学思维

题意:给你n 个数 ,让你找出其中有多少组数字   a 异或b   大于max(a, b) 题解:首先了解异或运算的方式    相同为0  不同为1    可以知道如果要增大肯定是要不同的位多于相同的位,其次需要知道     2的n次方等于2的n-1次访加到2的1次访再加1,即最高位影响大于低位之和,也就是说只有某个数字它和其他数字最大位不相同,则异或必然大于max(a, b): 代码: #include<stdio.h> #include<iostream> #include&l