E:给定 n,k,问是否可以构造一个 1~n 的排列 P,使得对于 1~n 中任意的数 i,P 都存在一个 长为 i 的子区间,其和模 n 余 k。有解输出任意一组,无解输出 -1。
等差数列求和,从1到n所有元素的和 = n*(n+1)/2.
所以,如果想结果存在的话,一定要满足所有元素的和 n*(n+1) / 2 % n = k
可得:如果n为偶数:那么k必须为n/2; 如果n为奇数,那么k必须为0
接下来就是序列的构造,因为要求长度从1到n的所有子序列和 % n = k。所以,我们需要凑n。
可以理解为:长度为1的子序列,一定是k本身。
长度为2的子序列: k,n
那么长度为3的子序列呢? 一定是k 与另外两个和为n的数字
长度为4:在3的基础上加上n。
所以:构造的序列就是将和为n的数字两两匹配输出即可
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 5e5 + 50;
int a[maxn];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n,k;
cin >> n >> k;
if(n % 2 == 0 && n/2 != k)
{
cout << -1 << endl;
}
else if(n % 2 == 1 && k != 0)
{
cout << -1 << endl;
}
else
{
cout << n << " ";
if(n % 2 == 0)
{
cout << n/2 << " ";
for(int i = 1; i < n/2; i++)
{
cout << i << " " << n-i << " ";
}
}
else
{
for(int i = 1; i <= n/2; i++)
{
cout << i << " " << n-i << " ";
}
}
// cout << (n+1)/2 << " ";
cout << endl;
}
return 0;
}
C:一个矩阵的底面积定义为最后一行的数的和,重量定义为所有数的和,给一个正整数矩阵,找一个“压强” 最大的可非连续子矩阵
一开始没想到是个贪心,思维题还是不够
找出最大的压强,可以想到:两列AB,假设A的压强大于等于B的压强。
那么AB合并之后,A的压强一定大于等于合并之后的压强。
所以,我们只需要看单独一列的压强即可。注意:列可以缩短。
所以o(nm)地去计算所有列,在所有长度时的压强大小,输出最大压强即可
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 250;
int a[maxn][maxn];
double sum[maxn][maxn];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
scanf("%d",&a[i][j]);
sum[i][j] = 0;
}
}
for(int j = 1; j <= m; j++)
{
for(int i = 1; i <= n; i++)
{
sum[i][j] = sum[i-1][j] + a[i][j];
}
}
double ans = 0;
for(int j = 1; j <= m; j++)
{
for(int i = 1; i <= n; i++)
{
sum[i][j] /= a[i][j];
}
}
for(int j = 1; j <= m; j++)
{
for(int i = 1; i <= n; i++)
{
ans = max(ans,sum[i][j]);
}
}
printf("%.8lf\n",ans);
}
return 0;
}
K: K-bag序列定义为由多个1-k的排列顺序连接起来的序列, 想问你给定序列是不是k-bag的连续子序列。
即:判断所给的序列,是否满足:
1.中间部分由长度为k,且数字不相同的序列构成。也可能没有完整的k序列
2.前后可能存在不完整的k序列
对于整个子序列,首先K的范围较大,需要进行离散化处理
1.如果出现了大于k的数字,那么肯定为NO
2.遍历整个序列,对于每一位数字i都维护一个窗口,用len[i]来记录从i开始,最长的不存在相同数字的序列长度。
3.枚举第一个完整k序列,或者最后一个不完整k序列的起点start
由记录的len[i]来判断是否符合要求,如果枚举到最后,符合要求,那么输出YES
补充:start的枚举范围:即:从1开始的最长序列len[1]+1以内都可能,其次不会超过k。所以取min
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int maxn = 5e5 + 50;
int a[maxn];
//int b[maxn];
int len[maxn];
int pre[maxn];
int main()
{
IOS;
int t;
cin >> t;
while(t--)
{
int n,k;
cin >> n >> k;
int ok = 1;
unordered_map<int,int> m;
int t = 1;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
// b[i] = a[i];
if(!m[a[i]])
{
m[a[i]] = t;
t++;
}
if(a[i] > k || a[i] < 0)
{
ok = 0;
}
}
if(!ok)
{
cout << "NO" << endl;
continue;
}
int num = 1;
for(int i = 1; i <= n; i++)//判断从i开始之后连续且不重复的数字有多少位
{//维护窗口
while(!pre[m[a[num]]] && num <= n)
{
pre[m[a[num]]]++;
num++;
}
pre[m[a[i]]]--;
//窗口后移一位
len[i] = num - i;
}
int sc = 0;
for(int start = 1; start <= min(k,len[1]+1); start++)
{
bool flag = true;
for(int i = start; i <= n; i += k)
{
if(i + len[i] >= n+1)
{
continue;
}
else if(len[i] != k)
{
flag = false;
break;
}
}
if(flag == true)
{
sc = 1;
break;
}
}
if(sc) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}