EPIC Institute of Technology Round Summer 2025 (Codeforces Round 1036, Div. 1 + Div. 2)(A~E)
期末周结束回归第二场,第一场(昨天)才做了三题,于是就没打算写了
A.Deranged Deletions
思路:题目问你是否能找到一个子数组,使得sort后,每个位置和原位置不同。显然只要存在一个逆序对即可有解,暴力即可(n很小),也可以用二分
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const ll N = 5e5 + 45;
const ll mod = 998244353;
ll ksm(ll x, ll y) {
ll ans = 1;
while (y) {
if (y & 1)ans = ans * x % mod;
x = x * x % mod;
y >>= 1;
}
return ans % mod;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
ll t;
cin>>t;
while(t--){
ll n;
cin>>n;
vector<ll>a(n+2,0);
vector<ll>b(n+2,0);
for(ll i=1;i<=n;i++)cin>>a[i];
b=a;
sort(b.begin()+1,b.begin()+1+n);
if(b==a)cout<<"NO"<<endl;
else {
cout<<"YES"<<endl;
cout<<2<<endl;
set<ll>d;
for(ll i=1;i<=n;i++){
auto j=d.upper_bound(a[i]);
if(j!=d.end()){
cout<<(*j)<<" "<<a[i]<<endl;
break;
}
d.insert(a[i]);
}
}
}
}
B.Minimise Sum
思路:分类讨论下,记住a[1]必拿。如果a[1]<a[2],那么可以假定a[3]放到了a[2],于是两个a[1]即为答案;如果a[1]=a[2],那么就把a[2]加到a[1]即可;如果a[1]>a[2],正常是a[1]+a[2],由于a[1]必拿,所以a[2]不要变即可,那么a[2]加到a[1]即可。
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const ll N = 5e5 + 45;
const ll mod = 998244353;
ll ksm(ll x, ll y) {
ll ans = 1;
while (y) {
if (y & 1)ans = ans * x % mod;
x = x * x % mod;
y >>= 1;
}
return ans % mod;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
ll t;
cin>>t;
while(t--){
ll n;
cin>>n;
vector<ll>a(n+2);
for(ll i=1;i<=n;i++)cin>>a[i];
if(a[1]==a[2]){
cout<<2*a[1]<<endl;
}
else if(a[1]>a[2]){
cout<<a[1]+a[2]<<endl;
}
else {
cout<<a[1]*2<<endl;
}
}
}
C.Subset Multiplication
思路:从后往前找。只关注a[i]%a[i-1]!=0,此时必定是a[i-1]乘zu以了x而a[i]没乘x,那么此时把两者的公约数求以下,寓意最大重合部分(a[i-1]最大可能值),随后把a[i-1]/公约数,得出一个小于等于x且是x的倍数的可能数,显然答案可以是所有这种数的lcm(最小公倍数)了。
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const ll N = 5e5 + 45;
const ll mod = 998244353;
ll ksm(ll x, ll y) {
ll ans = 1;
while (y) {
if (y & 1)ans = ans * x % mod;
x = x * x % mod;
y >>= 1;
}
return ans % mod;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
ll t;
cin>>t;
while(t--){
ll n;
cin>>n;
vector<ll>a(n+2);
for(ll i=1;i<=n;i++)cin>>a[i];
ll ans=1;
vector<ll>b;
for(ll i=n-1;i>=1;i--){
if(a[i+1]%a[i]==0)continue;
else {
b.push_back(a[i]/__gcd(a[i],a[i+1]));
}
}
if(b.size()==0)cout<<91<<endl;
else {
ll ans=0;
for(auto j:b){
if(ans==0)ans=j;
else {
ll u=__gcd(ans,j);
ans=ans*j/u;
}
}
cout<<ans<<endl;
}
}
}
D. Make a Palindrome
思路:我们先思考会,可以发现只要是全局数大于等于第k个的数都能删除(有些有个数限制)。那么我们可能把能全删除的删除,好了现在只剩下部分有个数限制的删除。由于只对一种数删除,那我们直接强构造回文串即可,每次不符合就考虑把能删除的数删除,并把conut--,最后得出一个数组,检测下是否回文即可
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const ll N = 5e5 + 45;
const ll mod = 998244353;
ll ksm(ll x, ll y) {
ll ans = 1;
while (y) {
if (y & 1)ans = ans * x % mod;
x = x * x % mod;
y >>= 1;
}
return ans % mod;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
ll t;
cin>>t;
while(t--){
ll n,k;
cin>>n>>k;
vector<ll>a(n+2),b(n+2);
for(ll i=1;i<=n;i++)cin>>a[i];
b=a;
sort(b.begin()+1,b.begin()+1+n);
vector<bool>vis(n+2,0),wz(n+2,0);
ll kk=0;
ll cnt=0;
for(ll i=k;i<=n;i++){
if(kk==0)kk=b[i],cnt++;
else if(kk==b[i])cnt++;
else vis[b[i]]=1;
}
ll len=0;
for(ll i=1;i<=n;i++){
if(vis[a[i]])continue;
else b[++len]=a[i];
}
ll l=1,r=len;
while(1){
if(cnt==0||l>=r)break;
else {
if(b[l]==b[r])l++,r--;
else {
if(kk==b[l])cnt--,wz[l]=1,l++;
else if(kk==b[r])cnt--,wz[r]=1,r--;
else break;
}
}
}
ll relen=0;
for(ll i=1;i<=len;i++){
if(wz[i])continue;
b[++relen]=b[i];
}
bool flag=0;
l=1,r=relen;
while(l<=r){
if(b[l]==b[r])l++,r--;
else {
flag=1;
break;
}
}
cout<<(flag==0?"YES":"NO")<<endl;
}
}
E.Make it Zero
思路:看了了个最大操作次数17,于是一直想二分,后面发现只要满足约束条件最大次数就是2.首先数组和必须为偶数,不然不可能最后变成0,其次就是最大值小于等于其他数之和(保证最大数能变为0)。只要上述两个条件满足,即可有解。第一次,我们直接选能分成两个部分的最小值最大的位置(找到max(min(pre[i-1],pre[n]-pre[i-1]))),随后直接先把小的处理,然后处理大的(如果两个部分值相等,显然只要一次),随后可以直接强构造大值区间两部分先相等,然后把剩下要减少的值平均分给两个区间,这样即可得到答案。
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const ll N = 5e5 + 45;
const ll mod = 998244353;
ll ksm(ll x, ll y) {
ll ans = 1;
while (y) {
if (y & 1)ans = ans * x % mod;
x = x * x % mod;
y >>= 1;
}
return ans % mod;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
ll t;
cin>>t;
while(t--){
ll n;
cin>>n;
vector<ll>a(n+2);
ll sum=0;
for(ll i=1;i<=n;i++)cin>>a[i],sum+=a[i];
if(sum&1)cout<<-1<<endl;
else {
ll flag=0;
for(ll i=1;i<=n;i++){
if(a[i]>sum-a[i]){
flag=1;
}
}
if(flag)cout<<-1<<endl;
else {
vector<ll>pre(n+4,0),del(n+4,0);
vector<ll>an[22];
for(ll i=1;i<=20;i++)an[i].resize(n+2,0);
// cout<<an[2][1]<<endl;
// return 0;
ll cs=0;
while(1){
for(ll i=1;i<=n;i++){
pre[i]=pre[i-1]+a[i];
del[i]=0;
}
if(pre[n]==0){
break;
}
cs++;
ll maxn=0;
ll wz=0;
for(ll i=1;i<=n;i++){//实际为1~i-1,i~n
ll u=min(pre[i-1],pre[n]-pre[i-1]);
if(maxn<u){
maxn=u;
wz=i;
}
}
ll l,r;
ll sum=maxn;
ll k=pre[n]-maxn;
if(maxn==pre[n]-maxn){
for(ll i=1;i<=n;i++)an[cs][i]=a[i];
break;
}
if(pre[wz-1]<=pre[n]-pre[wz-1]){
for(ll i=1;i<=wz-1;i++)an[cs][i]=0,a[i]=0;
l=wz,r=n;
}
else {
for(ll i=wz;i<=n;i++)an[cs][i]=0,a[i]=0;
l=1,r=wz-1;
}
for(ll i=l;i<=r;i++){
ll z1=pre[i]-pre[l-1];
ll z2=pre[r]-pre[i];
if(z1<=z2&&z1+maxn>=z2){
ll u=z2-z1;
maxn=maxn-u;
for(ll j=i+1;j<=r;j++){
if(a[j]>=u){
a[j]-=u;
break;
}
else u-=a[j],a[j]=0;
}
ll z=maxn/2;
for(ll j=l;j<=i;j++){
if(z==0)break;
if(z>=a[j])z-=a[j],a[j]=0;
else a[j]-=z,z=0;
}
z=maxn/2;
for(ll j=i+1;j<=r;j++){
if(z==0)break;
if(z>=a[j])z-=a[j],a[j]=0;
else a[j]-=z,z=0;
}
break;
}
else if(z1>=z2&&z2+maxn>=z1){
ll u=z1-z2;
maxn-=u;
for(ll j=l;j<=i;j++){
if(a[j]>=u){
a[j]-=u;
break;
}
else u-=a[j],a[j]=0;
}
ll z=maxn/2;
for(ll j=l;j<=i;j++){
if(z==0)break;
if(z>=a[j])z-=a[j],a[j]=0;
else a[j]-=z,z=0;
}
z=maxn/2;
for(ll j=i+1;j<=r;j++){
if(z==0)break;
if(z>=a[j])z-=a[j],a[j]=0;
else a[j]-=z,z=0;
}
break;
}
}
for(ll i=1;i<=n;i++)an[cs][i]=pre[i]-pre[i-1]-a[i];
}
cout<<cs<<endl;
for(ll i=1;i<=cs;i++){
for(ll j=1;j<=n;j++)cout<<an[i][j]<<" ";
cout<<endl;
}
}
}
}
}

浙公网安备 33010602011771号