场次链接
A. Equation
题目链接
给你一个数,让你给出两个合数a,b,使得a-b等于该数。
数据范围
1
≤
n
≤
1
0
7
1\leq n\leq 10^7
1≤n≤107,
1
≤
a
,
b
≤
1
0
9
1\leq a,b\leq 10^9
1≤a,b≤109
解
n
∗
9
−
n
∗
8
n*9-n*8
n∗9−n∗8即可,或者
n
∗
3
−
n
∗
2
n*3-n*2
n∗3−n∗2然后特判1。
复杂度
O
(
n
)
O(n)
O(n)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void work()
{
ll n;
scanf("%lld",&n);
if(n==1){
printf("9 8\n");
return;
}else{
printf("%lld %lld\n",n*3,n*2);
}
}
int main()
{
ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int T;
//scanf("%d",&T);
//cin>>T;
T=1;
while(T--){
work();
}
}
B. Modulo Equality
题目链接
首先一个n ,m,然后给n长度的a数组和b数组,b数组为a数组每个数加上同一个数之后%m,顺序不一定相同,问 加上的这个数为多少。
数据范围
1
≤
n
≤
2000
1\leq n\leq2000
1≤n≤2000,
1
≤
m
≤
1
0
9
1\leq m\leq 10^9
1≤m≤109,
0
≤
a
i
,
b
i
<
m
0\leq a_i,b_i<m
0≤ai,bi<m
解 a[1]一定对应一个b,所以枚举b,即枚举加上的这个数,然后开一个新的数组c存a+这个数,把b和c进行sort然后判断是否完全相同,然后求最小值就可以了。
复杂度
O
(
n
2
)
O(n^2)
O(n2)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[2005];
int b[2005];
int c[2005];
void work()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);
}
sort(b+1,b+n+1);
int ans=m;
for(int i=1;i<=n;i++){
int tmp=(b[i]-a[1]+m)%m;
for(int j=1;j<=n;j++){
c[j]=(a[j]+tmp)%m;
}
sort(c+1,c+n+1);
for(int j=1;j<=n;j++){
if(c[j]!=b[j]){
break;
}
if(j==n){
ans=min(ans,tmp);
}
}
}
printf("%d\n",ans);
}
int main()
{
ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int T;
//scanf("%d",&T);
//cin>>T;
T=1;
while(T--){
work();
}
}
C. Long Beautiful Integer
题目链接
给出n,k,然后给出为n长度的一个整数,然后你要给出一个数,这个数的要求为第i位与第i+k位相同,且要比给出的整数大的数中的最小的那个,输出数的长度和这个数的值。
数据范围
2
≤
n
≤
200000
2\leq n\leq 200000
2≤n≤200000,
1
≤
k
<
n
1\leq k< n
1≤k<n,
0
≤
a
i
≤
9
0\leq a_i\leq 9
0≤ai≤9
解 首先直接把给的数的前k位按顺序复制到后面,如果已经比后面大了,那么直接输出。否则 在第k位加一,那么前k-1位与原数相同,第k位比原数大,必定是满足题目要求的数。注意加1后超过9的情况。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
char a[200005];
char b[200005];
void work()
{
int n,m;
scanf("%d%d",&n,&m);
scanf("%s",a);
for(int i=0;i<n;i++){
b[i]=a[i%m];
}
if(strcmp(b,a)>=0){
printf("%d\n",n);
for(int i=0;i<n;i++){
printf("%c",b[i]);
}
printf("\n");
return;
}
int pos=m-1;
while(b[pos]=='9'){
b[pos]='0';
pos--;
}
b[pos]++;
printf("%d\n",n);
for(int i=0;i<n;i++){
printf("%c",b[i%m]);
}
printf("\n");
}
int main()
{
ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int T;
//scanf("%d",&T);
//cin>>T;
T=1;
while(T--){
work();
}
}
D. Domino for Young
题目链接
给你一个n长度的数组,例如给出a={3,2,2,2,1}时为下图。
你可以将一个12或者21的方块放到图中,问最多能放下几个方块。
数据范围
1
≤
n
≤
300000
1\leq n\leq 300000
1≤n≤300000 ,
1
≤
a
i
≤
300000
1\leq a_i\leq 300000
1≤ai≤300000,
a
i
+
1
≤
a
i
a_{i+1}\leq a_i
ai+1≤ai
解 首先如果前面没有格子剩余,那么如果出现一个偶数长度的点,可以直接放完;如果前面格子有剩余,出现一个偶数值的点,不会对格子的剩余有影响,但是会改变剩余格子的位置(画一画就知道了),每两个一循环。
如果前面没有格子剩余,出现一个奇数值的点,那么会在最下面多一个格子;
如果前面格子有剩余,出现一个奇数值的点,如果剩余的是最下面的格子,那么可以把这个格子用掉,如果剩余的是第二个格子,那么如果要补上那个格子,这列会空出2个格子,故删掉前面那个格子更优。然后画图可得若要出现第一种情况,2个奇数值的位置的奇偶性要不同。
所以对于值为奇数的位置,如果位置奇偶性不同,那么可以互补,全部填满,否则把多的删掉更优。
所以在该位置值为奇数时,记录一下位置的奇偶,然后答案就是
m
i
n
(
奇
,
偶
)
+
∑
i
=
1
n
a
[
i
]
/
2
min(奇,偶)+\sum_{i=1}^{n}a[i]/2
min(奇,偶)+∑i=1na[i]/2.
复杂度
O
(
n
)
O(n)
O(n)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[300005];
void work()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
ll ans=0;
int tmp1=0;
int tmp2=0;
for(int i=1;i<=n;i++){
ans+=a[i]/2;
if(a[i]%2==1){
if(i%2==0){
tmp1++;
}else{
tmp2++;
}
}
}
printf("%lld\n",ans+min(tmp1,tmp2));
}
int main()
{
ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int T;
//scanf("%d",&T);
//cin>>T;
T=1;
while(T--){
work();
}
}
E. K Integers
题目链接
给你一个n长度的从1到n的乱序排列,你可以交换相邻2个位置的值,然后要出现
1
,
2
,
3
,
4
,
…
…
,
k
1,2,3,4,……,k
1,2,3,4,……,k 这样的有序子段,对于k从1到n每个都输出最小的交换次数。
数据范围
1
≤
n
≤
200000
1\leq n\leq 200000
1≤n≤200000
解 首先 如果从i到i+k-1已经是1到k的排列,但是是乱序的,那么交换次数即这个序列中的逆序对的数量。那么就是将1到k聚集起来所需要的最少次数加上逆序对数量即可。要将1到k聚集起来,肯定是选最中间的点作为聚集点,两边都往中间靠。
先考虑计算逆序对数量,将值从1到n的位置加入一个树状数组,然后查找比它位置靠前的有多少个,即正序的数量,减一下即逆序数量。
再是将1到k聚集起来,用一个权值线段树,记录位置,从1到n循环时把当前的位置加入线段树,然后找到中点,设中点为p,那么在中点右边的要移到
p
+
1
,
p
+
2.
…
…
p+1,p+2.……
p+1,p+2.……,在中点左边的要移到
p
−
1
,
p
−
2
,
…
…
p-1,p-2,……
p−1,p−2,……,用权值线段树求出前
(
i
+
1
)
/
2
−
1
(i+1)/2-1
(i+1)/2−1个位置的和,即中点右边的和,减去
p
+
1
,
p
+
2
,
…
…
p
+
(
i
+
1
)
/
2
−
2
p+1,p+2,……p+(i+1)/2-2
p+1,p+2,……p+(i+1)/2−2的和,即右边要移动多少。同理求出左边的。
复杂度
O
(
n
log
n
)
O(n\log n)
O(nlogn)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[200005];
int tr[200005<<2];
ll sum[200005<<2];
int pos[200005];
int bit[200005];
ll pre[200005];
void add(int x)
{
for(int i=x;i<=200000;i+=i&(-i)){
bit[i]++;
}
}
int query(int x)
{
int sum=0;
for(int i=x;i>0;i-=i&(-i)){
sum+=bit[i];
}
return sum;
}
void update(int l,int r,int rt,int t)
{
if(l==r&&r==t){
tr[rt]++;
sum[rt]=l;
return;
}
int m=(l+r)>>1;
if(t<=m)update(l,m,rt<<1,t);
else update(m+1,r,rt<<1|1,t);
tr[rt]=tr[rt<<1]+tr[rt<<1|1];
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
int query1(int l,int r,int rt,int t)
{
//printf("%d %d\n",l,r);
if(l==r){
return l;
}
int m=(l+r)>>1;
if(t>tr[rt<<1|1])return query1(l,m,rt<<1,t-tr[rt<<1|1]);
else return query1(m+1,r,rt<<1|1,t);
}
ll query2(int l,int r,int rt,int t)
{
if(t==0)return 0;
if(l==r){
return sum[rt];
}
int m=(l+r)>>1;
ll ans=0;
//printf("%d %d %d %d\n",l,r,t,tr[m]);
if(t>tr[rt<<1|1])ans+=query2(l,m,rt<<1,t-tr[rt<<1|1])+sum[rt<<1|1];
else ans+=query2(m+1,r,rt<<1|1,t);
//printf("%d %d %lld\n",l,r,ans);
return ans;
}
void work()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
pos[a[i]]=i;
}
for(int i=1;i<=n;i++){
pre[i]=i-query(pos[i])-1;
add(pos[i]);
}
for(int i=1;i<=n;i++){
pre[i]+=pre[i-1];
}
printf("0");
update(1,n,1,pos[1]);
ll sum=pos[1];
for(int i=2;i<=n;i++){
ll tmp=pre[i];
update(1,n,1,pos[i]);
sum+=pos[i];
int mid=(i+1)/2;
int p=query1(1,n,1,mid);
//printf("p=%d\n",p);
//printf("%lld\n",tmp);
tmp+=query2(1,n,1,mid)-1ll*(p+p+mid-1)*(mid)/2;
//printf("???%d %lld %lld\n",mid,query2(1,n,1,mid),1ll*(p+p+mid-1)*(mid)/2);
//printf("%lld\n",tmp);
//printf("???%d %d %lld\n",mid,(p-1+p-i+mid)*(i-mid)/2,sum-query2(1,n,1,mid));
tmp+=1ll*(p-1+p-i+mid)*(i-mid)/2-(sum-query2(1,n,1,mid));
printf(" %lld",tmp);
}
printf("\n");
}
int main()
{
ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int T;
//scanf("%d",&T);
//cin>>T;
T=1;
while(T--){
work();
}
}