codeforces round696(div 2)题解(A-D)
A
对于两个0/1串,给定其串的长度和一个串a,求一个串b使,sum(a+b)=c最大,对于sum求得的新串c,规定c可以出现2,且c中的相同数字会被取代为一个。
很裸的一个贪心,对于b串的每一位从高位依次向下枚举,首选为1,若1能保证c中不相同,则令其为1,反之则为0。
#include<bits/stdc++.h>
#define MAXN 200000
using namespace std;
int T,n;
char a[MAXN];
int ans[MAXN];
void print()
{
for(int i=1;i<=n;i++)
printf("%d",ans[i]);
cout<<endl;
}
int main()
{
cin>>T;
ans[0]=100;
for(int i=1;i<=T;i++)
{
scanf("%d%s",&n,a+1);
a[0]='0';
for(int j=1;j<=n;j++)
{
if(a[j]+1-'0'!=a[j-1]+ans[j-1]-'0')
ans[j]=1;
else
ans[j]=0;
}
print();
}
return 0;
}
B
给定一个d,找出一个数a,使a满足:1.至少有四个因子。2.任意两个因子之间的差大于等于d
笔者此题被罚时两次,原因是我最开始只考虑了 a = ( 1 + d ) ∗ ( 1 + 2 d ) a=(1+d)*(1+2d) a=(1+d)∗(1+2d),却没有注意到1和1+d以及1+2d之间有可能存在其他因子,这样就不满足条件了。例如当d=4时, 1 ∗ ( 1 + 4 ) ∗ ( 1 + 2 ∗ 4 ) = 45 1*(1+4)*(1+2*4)=45 1∗(1+4)∗(1+2∗4)=45,但45却还有一个因子3,矛盾。
解决方法是需要保证a的两个最小质因子之间的距离和1与最小质因子之间的距离大于等于d,用欧拉筛打出素数表,再用lower_bound查找大于等于1+d和x1+d的最小质因子。
#include<bits/stdc++.h>
#define MAXN 200000
#define int long long
using namespace std;
inline int re()
{
char f=getchar();
int x=0,k=1;
while(f>'9'||f<'0')
{
if(f=='-') k=-1;
f=getchar();
}
while(f>='0'&&f<='9')
{
x=x*10+f-'0';
f=getchar();
}
return x*k;
}
int v[MAXN],prime[MAXN],cnt;
void prime_find(int x)
{
for(int i=2;i<=x;i++)
{
// cout<<i<<endl;
if(!v[i])
{
v[i]=i;
prime[++cnt]=i;
}
for(int j=1;j<=cnt;j++)
{
if(prime[j]*i>x) break;
v[prime[j]*i]=prime[j];
// cout<<j<<endl;
}
}
}
int T,n,ans[MAXN];
int pre(int x)
{
int t1=lower_bound(prime+1,prime+cnt+1,1+x)-prime;
int t2=lower_bound(prime+1,prime+cnt+1,prime[t1]+x)-prime;
return prime[t1]*prime[t2];
}
signed main()
{
T=re();
prime_find(200000);
while(T--)
{
n=re();
cout<<pre(n)<<endl;
}
return 0;
}
C
给出一个2n个数的序列,一开始你可以任选一个x值,然后在序列中找到两个数,使得这两个数的和等于x。然后删除这两个数,并让x等于这两个数中的最大值。直到整个序列全部被删除为止。求一个初始的x值,使序列能被完全删除。如果不能被完全删除,输出NO。
破题点在于:如果要将数列删除完 ,那必须保证每次删除的两个数中包含了a中的最大值,所以对于每一次的x我们只需要验证在剩余的数列中能否找到 ( x − m a x ( a ) ) (x-max(a)) (x−max(a))。又因为数据范围很小(1e3),所以我们可以枚举 a [ n ] + a [ i ] a[n]+a[i] a[n]+a[i]作为最开始的X0。
而对于验证操作,我们需要随时查询一个序列中的最大值和一个数是否在数列里面,并且还要对序列进行删减,我用(抄 )了stl中的multiset。这里说几个注意事项:
- multiset允许重复且保证有序
- s.find()返回的是一个迭代器,如果没有找到,则s.find()==s.end()
- s.end()并不是指向s中的最后一个元素,而是最后一个元素的下一位。
- 如果s.erase(5)会消除序列中所有的5,如果只想消除一个5,请在括号里写迭代器。
#include<bits/stdc++.h>
#define MAXN 3000
using namespace std;
inline int re()
{
char f=getchar();
int x=0,k=1;
while(f>'9'||f<'0')
{
if(f=='-') k=-1;
f=getchar();
}
while(f>='0'&&f<='9')
{
x=x*10+f-'0';
f=getchar();
}
return x*k;
}
int T,n,a[MAXN],k;
pair<int,int> ans[MAXN];
bool jud(int x)
{
multiset<int> q;
for(int i=1;i<=n;i++)
q.insert(a[i]);
k=0;
for(int i=1;i<=n/2;i++)
{
auto id=--q.end();
int p=*id;
q.erase(id);
x-=p;
id=q.find(x);
if(id==q.end())
return 0;
q.erase(id);
ans[++k]={x,p};
x=max(x,p);
}
return 1;
}
void print(int x)
{
cout<<"YES"<<endl;
cout<<x<<endl;
for(int i=1;i<=k;i++)
cout<<ans[i].first<<" "<<ans[i].second<<endl;
}
int main()
{
T=re();
while(T--)
{
n=re();
n*=2;
for(int i=1;i<=n;i++)
a[i]=re();
sort(a+1,a+n+1);
bool ans_find=0;
for(int i=1;i<n;i++)
{
if(jud(a[i]+a[n]))
{
ans_find=1;
print(a[i]+a[n]);
break;
}
}
if(!ans_find)
cout<<"NO"<<endl;
}
}
D
给出一段序列ai ,每次可以选择相邻的两个都不为0的ai 与 ai+1 令其都− 1 ,(这个操作可使用无限次)。在操作之前,你可以使用一次特权:交换相邻的两个数的位置(只能使用一次)。问是否可以将序列全部变为0 . 可以输出YES , 否则输出NO。
最开始的想法是分别求出奇数位的和和偶数位的和,再把数组相邻位的差逐一放入一个set中,在看这个set中找能否找到奇数位与偶数位之差。最后发现可以很轻松的举出反例:9,1,1,9;
正解:(借鉴了其他大佬的博客)
所以可以处理出前后缀,l[i]和r[i]。在不交换的情况下,若可以满足条件,即为l[n]==0.
如果产生交换,那我们只需要讨论一个新数组
l
[
i
−
1
]
,
a
[
i
+
1
]
,
a
[
i
]
,
r
[
i
+
2
]
l[i-1],a[i+1],a[i],r[i+2]
l[i−1],a[i+1],a[i],r[i+2] (交换i和i+1)能否符合条件,则其成立的条件是用奇数位与偶数位之和是否相等且中间的数比两边的数大。
有两个需要注意的地方:1.处理前后缀时要注意不存在的情况,即 a [ i ] − l [ i − 1 ] < 0 a[i]-l[i-1]<0 a[i]−l[i−1]<0,此时要将l[i]赋值为inf,r同理。 2.后缀标记不成立时要注意不能和前缀相同 , 比如 l[i] = inf / 2 ,那r[i]=inf , 否则无法区分 。
#include<bits/stdc++.h>
#define MAXN 300000
#define int long long
using namespace std;
inline int re()
{
char f=getchar();
int x=0,k=1;
while(f>'9'||f<'0')
{
if(f=='-') k=-1;
f=getchar();
}
while(f>='0'&&f<='9')
{
x=x*10+f-'0';
f=getchar();
}
return x*k;
}
int T,n,a[MAXN],l[MAXN],r[MAXN];
signed main()
{
T=re();
while(T--)
{
n=re();
for(int i=1;i<=n;i++)
a[i]=re();
memset(l,0,sizeof(l));
memset(r,0,sizeof(r));
if(n==1)
{
cout<<"NO"<<endl;
continue;
}
for(int i=n;i>=1;i--)
if(a[i]>=r[i+1]) r[i]=a[i]-r[i+1];
else r[i]=(int)1e18;
for(int i=1;i<=n;i++)
if(a[i]>=l[i-1]) l[i]=a[i]-l[i-1];
else l[i]=(int)1e18/2;
if(l[n]==0)
{
cout<<"YES"<<endl;
continue;
}
bool ans_find=0;
for(int i=1;i<n;i++)
{
if(l[i-1]+a[i]==a[i+1]+r[i+2]&&l[i-1]<=a[i+1]&&a[i]>=r[i+2])
{
ans_find=1;
break;
}
}
if(ans_find)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
}