D.守恒
阿宁有一个长度为 n 正整数数组 a。
可以进行任意次操作,每次操作选择数组 a 的两个元素,其中一个加 1,另一个减 1,要求每次操作后 a 的各元素仍然是正整数。
阿宁想知道操作结束后,数组的最大公约数可能有多少种不同的值?
数组的最大公约数指,该数组的所有数共有约数中最大的那个数。
例如数组 [20,12,16],共有的约数有 1,2,4,最大的数是 4,因此 [20,12,16] 的最大公约数是 4。
输入
第一行输入一个整数 n (1 ≤ n ≤ 2e5)。
第二行输入 n 个整数 ai (1 ≤ ai ≤ 2e5)。
输出
输出一个整数。
Input
3
2 4 8
Output
2
解析:
因为加一减一,和是不变的。
假设这些数的和是sum,这道题的本质上就是求,在sum的因子中,有多少个因子能把sum分解的个数是大于等于 n 个的。
当然,当 n=1时,要特判一下。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define ios ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int gcd(int a,int b) { return b? gcd(b,a%b) : a; }
typedef pair<int,int> PII;
const double PI=acos(-1.0);
const int N=2e5+10;
int n;
int a[N];
void solve()
{
cin>>n;
int sum=0;
for (int i=1;i<=n;i++) cin>>a[i],sum +=a[i];
if (n==1)
{
cout<<1;
return ;
}
int cnt=0;
for (int i=1;i<=sum/i;i++)
{
if (sum%i==0)
{
if (i*i==sum)
{
if (sum/i>=n) cnt++;
}
else
{
if (sum/i>=n) cnt++;
if (i>=n) cnt++;
}
}
}
cout<<cnt;
}
signed main()
{
ios;
int T=1;
//cin>>T;
while (T--) solve();
return 0;
}
E.漂亮数组
阿宁认为一个数组是漂亮数组,该数组需要存在一个总和是 k 的倍数的子数组。
现在阿宁有一个长度为 n 的数组 a,阿宁想要将数组 a 分割出若干个数组。
分割出的数组需要满足,按照分割顺序合并可以得到原数组a。
阿宁想知道将数组 a 分割,最多可以获得多少个漂亮数组?
输入
第一行输入两个整数 n,k (1 ≤ n ≤ 2e5,1 ≤ k ≤ 1e9)。
第二行输入 n 个整数 ai (1 ≤ ai ≤1e9)。
输出
输出一个整数。
Input
6 3
1 1 4 5 1 4
Output
2
解析:
贪心,对于 i 找它的左边离他最近的 j 使 [j,i] 的和为 k 的倍数。
前往后遍历,如果(从上个割点开始的)前缀和对 k 的余数,在位置 j 和位置 i 的相同,说明区间 [j+1,i]的和能整除 k ,(其中 j<i)。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define ios ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int gcd(int a,int b) { return b? gcd(b,a%b) : a; }
typedef pair<int,int> PII;
const double PI=acos(-1.0);
const int N=510;
set <int> s;
int n,k;
void solve()
{
cin>>n>>k;
int x,sum=0;
s.insert(0);
int cnt=0;
for (int i=1;i<=n;i++)
{
cin>>x;
sum +=x;
if (s.count(sum%k)) cnt++,sum=0,s.clear(),s.insert(0);
else s.insert(sum%k);
}
cout<<cnt;
}
signed main()
{
ios;
int T=1;
//cin>>T;
while (T--) solve();
return 0;
}
G.数三角形(easy)
阿宁认为一个大小为 x 的等腰三角形底边长度是 2×x+1,高是 x+1。
等腰三角形不可以旋转,并且形态只能是下面举例的形态。
以下分别是 1,2,3 的等腰三角形:
在一个字符矩阵中,三角形可以共用 '*'。因此上述举例中,大小为 2 和大小为 3 的三角形,都有两个大小为 1 的三角形。
现在给出一个 n 行 m 列的仅包含 '*' 和 '.' 的矩阵, 阿宁想要数一下有多少个满足要求的等腰三角形?
输入
第一行输出两个整数 n,m (1 ≤ n,m ≤ 500),表示字符矩阵大小。
接下 n 行,每行 m 个字符,表示所给的矩阵。字符仅包含 '*' 和 '.'。
输出
输出一个整数,表示等腰三角形的数量。
Input1
3 5
..*..
.*.*.
*****
Output1
3
Input2
3 5
..*..
.***.
*****
Output2
5
解析:
枚举三角形的最上面那个点,然后用一个前缀和来看下面是否有一条线。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define ios ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int gcd(int a,int b) { return b? gcd(b,a%b) : a; }
typedef pair<int,int> PII;
const double PI=acos(-1.0);
const int N=510;
char g[N][N];
int s[N][N];
int n,m;
void solve()
{
cin>>n>>m;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
cin>>g[i][j];
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
s[i][j]=s[i][j-1];
if (g[i][j]=='*') s[i][j]++;
}
int cnt=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
if (g[i][j]=='*')
{
int k=i+1,l=j-1,r=j+1;
while (k<=n&&l>=1&&r<=m&&g[k][l]=='*'&&g[k][r]=='*')
{
if (s[k][r]-s[k][l-1]==r-l+1) cnt++;
k++,l--,r++;
}
}
}
cout<<cnt;
}
signed main()
{
ios;
int T=1;
//cin>>T;
while (T--) solve();
return 0;
}