1.K - 比赛 1228 (qingyandark.top)
思维题,读题需要好好审清楚问题。
首先是没理解“编号与自己差值不大于 2”,只需要考虑相邻三个不能重复,每三个一循环,循环的数字可以循环内调整,多个循环的数字排列必须保持一致。
其次是gcd(x,y)=1,就是2,3,5
构成:2 3 5 2 3 5...,2 5 3 2 5 3...,...等等
最后一点就是,n=1的时候需要特判。
思维的分类讨论:
余0: 完整,有6种。
余1:保证余的最小,是2,所以2 3 5、2 5 3,2种情况
余2: 保证余的最小,是2、3,所以是2 3 5、3 2 5两种情况
int n,a[3]={2,5,10};
scanf("%d",&n);
if(n = 1)
puts("2 1");
else
printf("%d %d\n",(n-1)/3*10+a[(n-1)%3],n%3?2:6);
2.B - 比赛 1228 (qingyandark.top)
这道题没有完整思考出解决方案
只思考了需要连续的一段进行计算和,但是应该是在去除这一段后将其左右两段加和,合并成一段--左右两个位置的都是一个属性,这一点没有想到
可以使用vector,然后进行擦除进行操作,也可使用数组。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+10;
int n,a,b;
char s[8050];
int val[8050],tot=0;
void input()
{
scanf("%d%d%d%s",&n,&a,&b,s);
int cnt=1;
for(int i=1;i<n;i ++ )
{
if(s[i] != s[i-1])
{
val[ ++ tot]=cnt*(s[i-1] == 'A'?a:b);
cnt=1;
}
else
cnt ++ ;
}
val[ ++ tot]=cnt*(s[n-1] == 'A'?a:b);
}
void solve()
{
int ans[2]={0,0},cur=1;
while(tot != 0)
{
int mx=0,mxp=0; //最大权值及其所在位置
for(int i=1;i <= tot;i ++)
if(val[i]>mx)
{
mx=val[i];
mxp=i;
}
ans[cur]+=mx; //加入答案
cur^=1;
if(mxp == 1) //在首位置,把该位置权值删去,其余权值左移一格即可
{
for(int i=1;i<tot;i ++ )
val[i]=val[i+1];
tot -- ;
}
else if(mxp == tot) //在尾位置,无需处理
{
tot -- ;
}
else // 在中间,需要将左右两边权值合并,并把右侧权值左移两格
{
val[mxp-1]+=val[mxp+1];
for(int i=mxp;i<tot-1;i++ )
val[i]=val[i+2];
tot-=2;
}
}
printf("%d %d\n",ans[0],ans[1]);
}
int main()
{
input();
solve();
return 0;
}
3.C - 比赛 1228 (qingyandark.top)
C题待补,set上自动排序不会写,还需要存一下位置。
如下为C题标程
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+10;
struct node
{
int val,pos;
node(){}
node(int val,int pos):val(val),pos(pos){}
bool operator < (const node& a) const // 按题意对权值和下标进行排序
{
if(val^a.val)return val>a.val;
return pos<a.pos;
}
bool operator == (const node& a) const
{
return val == a.val && pos == a.pos;
}
};
int n,a,b;
char s[200050];
int val[200050];
set<node> sval; //存储权值及下标
set<int> spos; //维护下标,递增
void input()
{
scanf("%d%d%d%s",&n,&a,&b,s);
int cnt=1;
for(int i=1;i<n;i ++ )
{
if(s[i] != s[i-1])
{
val[i-cnt]=cnt*(s[i-1] == 'A'?a:b);
sval.insert(node(val[i-cnt],i-cnt));
spos.insert(i-cnt);
cnt=1;
}
else
cnt ++;
}
val[n-cnt]=cnt*(s[n-1] == 'A'?a:b);
sval.insert(node(val[n-cnt],n-cnt));
spos.insert(n-cnt);
}
void solve()
{
int ans[2]={0,0},cur=1;
while(!sval.empty())
{
auto it=sval.begin(); //每次取集合顶部加入答案
ans[cur]+=(*it).val;
cur^=1;
if(spos.size()>1)
{
auto itt=spos.find((*it).pos);
if(itt != spos.begin() && itt != ( -- spos.end())) //如果不是首尾元素
{
auto lef=itt; lef -- ; //取左侧指针
auto rig=itt; rig ++ ; //取右侧指针
auto lefval=sval.find(node(val[*lef],*lef)); //返回sval集合找出左侧元素
auto rigval=sval.find(node(val[*rig],*rig)); //返回sval集合找出右侧元素
node nd=*lefval;
nd.val+=(*rigval).val; //合并左右侧元素
val[*lef]+=(*rigval).val;
sval.insert(nd); //插入原集合中
sval.erase(lefval); //并将原本的两相邻元素删除
sval.erase(rigval);
spos.erase(rig); //对于spos集合,删除右侧下标即可
}
spos.erase(itt);
}
sval.erase(it);
}
printf("%d %d\n",ans[0],ans[1]);
}
int main()
{
input();
solve();
return 0;
}