题目:A. Omkar and Completion
直接构造相同的数。
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define MAX_len 200005*4
using namespace std;
typedef long long ll;
typedef pair<int,int> PP;
const int mod=998244353;
const int MAXlen=1e5+10;
long double eps=1e-9;
int a[1010];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int i,n,j;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
printf("1 ");
}
printf("\n");
}
return 0;
}
题目:B. Omkar and Last Class of Math
题意:a+b=n,找到min(LCM(a,b))。
直接去枚举gcd(a,b)的因子,
t
1
∗
x
+
t
2
∗
x
=
n
,
l
c
m
=
t
1
∗
t
2
∗
x
t1*x+t2*x=n,lcm=t1*t2*x
t1∗x+t2∗x=n,lcm=t1∗t2∗x,而
t
2
∗
t
1
t2*t1
t2∗t1最小的时候即有一位为1(即
(
y
−
t
1
)
∗
t
1
(y-t1)*t1
(y−t1)∗t1的最小值)。
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define MAX_len 200005*4
using namespace std;
typedef long long ll;
typedef pair<int,int> PP;
const int mod=998244353;
const int MAXlen=1e5+10;
long double eps=1e-9;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
ll i,n,j;
ll a1,a2;
scanf("%I64d",&n);
a1=1,a2=n-1;
ll ans=n-1;
for(i=2;i*i<=n;i++)
{
if(n%i==0)
{
if(ans>(i-1)*(n/i))
{
ans=(i-1)*(n/i);
a1=n/i*1,a2=n/i*(i-1);
}
}
}
printf("%I64d %I64d\n",a1,a2);
}
return 0;
}
题意:求把给定数组变换为1-n的顺序排列,变换可选择一段区间,变换完不能在相同的位置有跟变换之前相同的数。
可以发现,如果变换完跟1-n这个顺序完全没有一个相同的,变换一次即可。
任何顺序的若初始有a[i]=i,那么多加一次变换,把a[i]=i的与任意a[i]!=i(或和a[i]=i)的交换,最多2次全换完。
特殊处理一下首尾的情况。
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define MAX_len 200005*4
using namespace std;
typedef long long ll;
typedef pair<int,int> PP;
const int mod=998244353;
const int MAXlen=1e5+10;
long double eps=1e-9;
int a[200100];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,i,j;
scanf("%d",&n);
int sum=0;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]==i)
sum++;
}
if(!sum)
{
printf("1\n");
continue;
}
else if(sum==n)
{
printf("0\n");
continue;
}
for(i=1;i<=n;i++)
{
if(a[i]==i)
sum--;
else
break;
}
for(i=n;i>=1;i--)
{
if(a[i]==i)
sum--;
else
break;
}
if(!sum)
printf("1\n");
else
printf("2\n");
}
return 0;
}
题意:给了一个长度为n的圆排列,拿走a[i],则a[i-1]和a[i+1]的和取代a[i]位置,直到还剩余一个数。求最大值。
首先肯定拿的次数为n/2,进而分析,拿的数字都不是相邻的,为什么?因为如果拿了相邻的原本是再整个排列的总和中减去一个数,拿相邻的就减去两个数了,不符合要最大的策略。式子表示就是sum-x1-x2-x3-x5<sum-x1-x5。
分成奇偶的情况进行枚举,中途可以有一次拿间隔是3的。
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define MAX_len 200005*4
using namespace std;
typedef long long ll;
typedef pair<int,int> PP;
const int mod=998244353;
const int MAXlen=1e5+10;
long double eps=1e-9;
int a[400100];
ll sum1[200100];
ll sum2[200100];
int main()
{
int n,i,j;
ll sum=0;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
a[n+i]=a[i];
}
sum1[0]=sum2[0]=0;
for(i=1;i<=n;i++)
{
if(i&1)
{
sum1[i]=sum1[i-1]+a[i];
sum2[i]=sum2[i-1];
}
else
{
sum1[i]=sum1[i-1];
sum2[i]=sum2[i-1]+a[i];
}
}
if(n==1)
{
printf("%d",a[1]);
return 0;
}
int temp=n/2;
ll ans=sum-sum2[n];
for(i=1;i<n;i+=2)
{
ans=max(ans,sum-(sum1[i]+sum2[n]-sum2[i+1]));
}
for(i=n;i>1;i-=2)
{
ans=max(ans,sum-(sum1[n]-sum1[i-2]+sum2[i-2]));
}
for(j=2;j<=n;j+=2)
{
ans=max(ans,sum-(sum2[i]+sum1[n]-sum1[i+1]));
}
printf("%I64d\n",ans);
return 0;
}
题目:E. Omkar and Last Floor
题意:给定了
n
∗
m
n*m
n∗m的矩阵,n为行数。给定每行的分割区间值,每个区间可以放一个1。求
∑
i
=
1
m
q
i
2
{\sum_{i=1}^mq_i}^2
∑i=1mqi2的最大值。
毫无疑问一列全满的时候贡献最大。区间dp,
设dp[i][j]:从i列到j列的最大值。这么直接做貌似写起来很麻烦。
每一段区间中的1都是可以转移的,所以当第k列的第某行的左右端点都在i-j中的时候直接找所有1集中的贡献。
dp[i][j]:表示i–j列区间所包含区间的最大贡献。
举个栗子:枚举第k列的时候,由于有3行该点的区间端点是i-j的子集,则我们可以将他们移动到一起,那么该区间dp[i][k-1]以及dp[k+1][j]就不能算他们的贡献了,所以变完有3行该点的区间端点就不是k+1–j和i–k+1的子集了就不能算贡献了。
女少口阿。
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define MAX_len 200005*4
using namespace std;
typedef long long ll;
typedef pair<int,int> PP;
const int mod=998244353;
const int MAXlen=1e5+10;
long double eps=1e-9;
int a[110][110];
int dp[110][110];
int L[110][110],R[110][110];
int main()
{
int n,m,i,j;
scanf("%d %d",&n,&m);
for(i=1;i<=n;i++)
{
int temp;
scanf("%d",&temp);
while(temp--)
{
int l,r;
scanf("%d %d",&l,&r);
for(j=l;j<=r;j++)
{
L[i][j]=l;
R[i][j]=r;
}
}
}
for(int len=1;len<=m;len++)
{
for(i=1;i+len-1<=m;i++)
{
int RR=i+len-1;
for(int k=i;k<=RR;k++)
{
int sum=0;
for(j=1;j<=n;j++)
{
if(L[j][k]>=i&&R[j][k]<=RR)
{
sum++;
}
}
dp[i][RR]=max(dp[i][RR],dp[i][k-1]+dp[k+1][RR]+sum*sum);
}
}
}
printf("%d",dp[1][m]);
return 0;
}