1913. 两个数对之间的最大乘积差
- 题目大意
在一个长度为n的序列中找出4个数使得 a ∗ b − c ∗ d a*b-c*d a∗b−c∗d最大。 - 思路
- code
class Solution {
public:
int maxProductDifference(vector<int>& nums) {
int n = nums.size();
sort(nums.begin(), nums.end());
return nums[n-1]*nums[n-2]-nums[0]*nums[1];
}
};
1914. 循环轮转矩阵
- 题目大意
给一个n*m的矩阵,给一个k,输出每一层(从外到里分层)逆时针转k圈后的矩阵。 - 思路
模拟 写了好久 烦 - code
class Solution {
public:
vector<vector<int>> rotateGrid(vector<vector<int>>& grid, int k) {
int n = grid.size(), m = grid[0].size();
int ans[55][55]={0};
int ceng=min(n,m)/2;
int nn=n, mm=m;
for(int i=0;i<ceng;i++)
{
int num=2 * nn + 2 * (mm - 2);
int kk=k%num;
cout<<kk<<endl;
for(int j=1;j<=kk;j++)
{
for(int x=i;x<n-i-1;x++){
ans[x+1][i]=grid[x][i];
}
for(int y=i;y<m-i-1;y++){
ans[n-i-1][y+1]=grid[n-i-1][y];
}
for(int x=n-i-1;x>i;x--){
ans[x-1][m-i-1]=grid[x][m-i-1];
}
for(int y=m-i-1;y>i;y--){
ans[i][y-1]=grid[i][y];
}
//重新装回grid数组
for(int x=i;x<n-i-1;x++){
grid[x][i]=ans[x][i];
}
for(int y=i;y<m-i-1;y++){
grid[n-i-1][y]=ans[n-i-1][y];
}
for(int x=n-i-1;x>i;x--){
grid[x][m-i-1]=ans[x][m-i-1];
}
for(int y=m-i-1;y>i;y--){
grid[i][y]=ans[i][y];
}
}
nn-=2,mm-=2;
}
return grid;
}
};
1915. 最美子字符串的数目
-
题目大意
给定长度为n的仅含有小写字母 a − j a-j a−j的字符串,求“漂亮子字符串”的数量。定义漂亮字符串:最多有一个字母的个数为奇数。 -
思路
最简单考虑 O ( n 2 ) O(n^2) O(n2)的DP,优化:把对于目前状态一样的状态放到一起统计。
用10位二进制数表示每个字母出现的奇偶性。
p r e [ i ] pre[i] pre[i]表示0-i位的子串的奇偶性数字。
p r e [ i ] = p r e [ i − 1 ] ⊕ ( 1 < < w o r d [ i ] ) pre[i]=pre[i-1] \oplus (1<<word[i]) pre[i]=pre[i−1]⊕(1<<word[i])。
使用map记录每个状态在之前出现了多少次。
统计答案:
1.遍历每一个字母在二进制数状态的位置,分别使其翻转(其他的字母奇偶性相同,只有这一位奇偶相反相减为奇数);表示前面有一段区间的字符串奇偶性满足条件。
2.前面存在与目前状态一致(奇数-奇数=偶数, 偶数-偶数=偶数)的字符串段答案也要统计。 -
code
class Solution {
public:
long long wonderfulSubstrings(string word) {
#define ll long long
#define N 100010
int n = word.size();
int s[N];
int pre[N]={0};
map<int,ll> mp;
pre[0] = 1<<(word[0]-'a');
mp[0]=1;
mp[pre[0]]++;
ll ans=1;
for(int i=1;i<n;i++)
{
pre[i]=pre[i-1] ^ (1<<(word[i]-'a'));
ans+=mp[pre[i]];
for(int j=0;j<10;j++) ans+=mp[pre[i]^(1<<j)];
mp[pre[i]]++;
}
return ans;
}
};
1916. 统计为蚁群构筑房间的不同顺序
- 题目大意
蚂蚁盖房子,房子有n个房间,每个房间有一个唯一的先序房间(即只有他的先序房间建完了之后才能建他),0号房间已经建好了。问有多少种合法的建房间序列,答案对 1 e 9 + 7 1e9+7 1e9+7取余 - 思路
考虑1-n构成的任意排列中,有多少种排符合 1 − m − 1 ( m < n ) 1-m-1(m<n) 1−m−1(m<n)在 m m m之前:
只需考虑m在这m个数中的最后位置的序列数即可。这m个数中每个数在m个数最后面的概率相等,即均为 1 m \frac{1}{m} m1。因此m在m个数最后的概率是 1 m \frac{1}{m} m1。因此在 n ! n! n!排列中满足要求的数量为 n ! m \frac{n!}{m} mn!。
\
由于合法的建房间序列是 n ! n! n!种排列中的一些,并且对于每个前驱来说只要满足他在他的所有后继之前被建造就是合法的,即对于每个节点 i i i来说他在他的后继之前被建造就相当于他排在所有后继的最前面,其概率为 1 s i z e [ i ] \frac{1}{size[i]} size[i]1。并且每个前驱的计算互相不影响,即答案满足乘法原理,
所以最终的答案是 n ! ∏ i = 0 n − 1 s i z e [ i ] \frac{n!}{\prod \limits_{i=0}^{n-1}{size[i]}} i=0∏n−1size[i]n!。
\
注意除法取余操作。 - code
class Solution {
#define N 100010
#define mod 1000000007
#define ll long long
ll sz[N]={0},fac[N]={0},mul[N]={0};
int n;
vector<int> v[N];
int dfs(int x)
{
sz[x]=1;
for(auto i:v[x]) sz[x]=sz[x]+dfs(i);
return sz[x];
}
ll quikp(ll x, ll p)
{
ll ans=1;
while(p)
{
if(p%2) ans = (ans * x) % mod;
p>>=1;
x=x*x%mod;
}
return ans;
}
public:
int waysToBuildRooms(vector<int>& prevRoom) {
n = prevRoom.size();
for(int i=1;i<n;i++) v[prevRoom[i]].push_back(i);
dfs(0);
fac[0]=1;mul[0]=sz[0];
//for(int i=0;i<n;i++) cout<<sz[i]<<endl;
for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;
for(int i=1;i<n;i++) mul[i]=mul[i-1]*sz[i]%mod;
//for(int i=0;i<n;i++) cout<<mul[i]<<' ';
return fac[n]*quikp(mul[n-1],mod-2)%mod;
}
};