战绩and总结
发现D大模拟有bug的时候,发现E可以做,调到最后三十秒交wa了心态都蹦了,赛后十分钟过了E 😦 太难见到比较简单的1700分的题了
A. Integer Sequence Dividing
题意:给你一个数n,求把1~n的整数分为两组,使得每组的和的差的绝对值最小。
思路:比赛的时候枚举推出了正解,但是我写的比较复杂也不知道证明,这里贴一个:每当n+4时,必然可以将多出来的4个值分为n+1和n+4 与 n+2和n+3,所以差不变,所以往n%4去想
n%4=3时,1 2 3 的差值为0,所以也是0
n%4=2时,1 2 显然差1
n%4=1时,同上,差为1
n%4=0时,差值为0
#include<iostream>
using namespace std;
int main()
{
int a;
cin>>a;
if(a%4==0){cout<<'0';return 0;}
if(a%4==2){cout<<'1';return 0;}
if(a%4==3){cout<<'0';return 0;}
if(a%4==1){cout<<'1';return 0;}
return 0;
}
B. Array K-Coloring
题意:长为n的序列a和k种颜色,要求①每个元素都要被染色,②每种颜色都要被使用,③每种颜色不会用于相同的元素。
思路: 我暴力模拟的就不贴了,看到了一个比较牛的思路贴一下:
解决问题有两个:
1.用上所有颜色
2.每种相同数字的颜色不同
对于第一个,简单地,只需设置一个变量color,一直++,超过了颜色数就再次从1开始
对于第二个,为了让相同数字排在一起我们需要一次sort,之后就只要保证该种数字的数量小于颜色数就好了
对于输出,按照读入顺序再次sort即可
(感觉使用暴力的我智商受到了侮辱Orz
const int maxn=5005;
int a[maxn];
int ans[maxn];
int main()
{
int n,i,j,k,max1=0,mm;
cin>>n>>k;
bool flag=0;
map<int ,int >mo;
for(i=0;i<n;i++){
cin>>a[i];
mo[a[i]]++;
if(mo[a[i]]>max1)
{
max1=mo[a[i]];
mm=a[i];
}
if(max1>k) {
flag=1;
}
ans[i]=mo[a[i]];
}
if(flag==0&&n>=k)
{
scYES;
if(max1==k)
{
for(i=0;i<n;i++)
{
if(ans[i]==0)
ans[i]=1;
}
}
else
{
for(i=0;i<n;i++)
{
if(a[i]!=mm&&max1<k)
ans[i]=++max1;
}
}
for(i=0;i<n-1;i++) cout<<ans[i]<<" ";
cout<<ans[i]<<endl;
}
else
{
scNO;
}
}
C. Doors Breaking and Repairing
题意:给你一个含有N个数的数组,每一个元素代表一个门的当前防御值。
每一次你可以对门进行攻击,降低x个点数的防御值;而你的对手(斯拉维克)可以对门进行修复,提升y个点数的防御值。
当一次你对门的攻击使这个门的防御值小于等于0的时候,这个门就坏掉了,就再也没法修复了。
问:当你和对手都采取最优的策略的时候,你最多可以砸坏几个门?
思路:
如果 x > y,所有门的总血量每回合都会减少,经过无限个回合,所有的门一定都会被打破。
否则就是 x≤y 的情况,发现那些血量 > x的门A永远打不破,因为A打一下,B就可以加固那扇门,血量 ≤x 的门,A打破一扇,B就加固一扇门,A只能打破一半(A先手,要上取整)
const int maxn=1e5+100;
int a[maxn];
int main()
{
int x,y,n,i,j;
cin>>n>>x>>y;
for(i=0;i<n;i++)
{
cin>>a[i];
}
if(x>y)
{
cout<<n<<endl;
}
else
{
double cnt=0;
for(i=0;i<n;i++)
{
if(a[i]<=x)
{
cnt++;
}
}
cout<<(int)(cnt/2+0.5)<<endl;
}
}
D. Balanced Ternary String
题意:给出一个长为n的只由’1’,‘2’,‘0’组成的字符串,要求改动最少的位置,使’1’,‘2’,'0’的个数相同(保证n能被3整除),并使改动后的字符串字典序最小。输出改动之后的字符串
思路:由于我这个贪心贪少了,所以贴贴大佬的思路,我是在三种情况的顺序上出现了问题。
#include <cstdio>
int n, qui;
char s[300005];
int cnt[105];
// 注意每次修改元素后要及时修改 cnt 数组
int main() {
scanf("%d", &n);
qui = n/3;
scanf("%s", s+1);
for(int i = 1; i <= n; ++i)
++cnt[(int)s[i]];
for(int i = 1; cnt['2'] > qui && i <= n; ++i) {
if(s[i] == '2') {
if(cnt['0'] < qui) s[i] = '0', ++cnt['0'], --cnt['2'];
else if(cnt['1'] < qui) s[i] = '1', ++cnt['1'], --cnt['2'];
}
}
for(int i = n; cnt['0'] > qui && i; --i) {
if(s[i] == '0') {
if(cnt['2'] < qui) s[i] = '2', ++cnt['2'], --cnt['0'];
else if(cnt['1'] < qui) s[i] = '1', ++cnt['1'], --cnt['0'];
}
}
for(int l = 1, r = n; cnt['1'] > qui && r; ++l, --r) {
if(s[l] == '1' && cnt['0'] < qui) s[l] = '0', ++cnt['0'], --cnt['1'];
if(s[r] == '1' && cnt['2'] < qui) s[r] = '2', ++cnt['2'], --cnt['1'];
}
puts(s+1);
return 0;
}
E. Monotonic Renumeration
题意:定义一个数组a的b数组为满足下列条件的数组
①b[1]=0
②如果ai=aj,那么bi=bj
③b[i]=b[i-1]+1 或者 b[i]=b[i−1]
给出a,求合法的b的数量 %998244353
思路:首先看题目给出的条件,模拟去构造一下B,因为第三点可知这个数列一定是个非递减序列,并且如果ai=aj的话,那么这个区间上所有的b的值都唯一那么计算数量的时候就可以从这里入手,假设长度为n的a数组里所有的数都不同,那么对应的b数组的个数应该就是2^n次方,因为每个b[i+1]的取值都可以是b[i]或者b[i]+1,所以只要记算一下b区间里不重复的个数就行
那么怎么计算呢?可以把它转化为区间合并问题,看最后b数组能分成cnt个不相交的区间,最后结果就是2^cnt-1%998244353了
#define int long long
const int maxn=2e5+1000;
int a[maxn];
struct node {
int l,r;
}mo[maxn],ly[maxn];
bool cmp1(node a,node b)
{
return a.l<b.l;
}
signed main()
{
int n,i,j;
cin>>n;
map<int ,int >m2;
map<int ,pair<int ,int >>m1;
for(i=0;i<n;i++){
cin>>a[i];
m2[a[i]]++;
if(m2[a[i]]==1)
m1[a[i]].first=i+1,m1[a[i]].second=i+1;
else
m1[a[i]].second=i+1;
}
int cnt=0;
for(auto x:m1)
{
mo[cnt].l=m1[x.first].first;
mo[cnt++].r=m1[x.first].second;
}
sort(mo,mo+cnt,cmp1);
int cnt1=0,z1=0;
for(i=0;i<cnt;i++)
{
if(mo[i].l>ly[max(cnt1-1,0ll)].r)
{
ly[cnt1].l=mo[i].l;
ly[cnt1].r=mo[i].r;
cnt1++;
}
else
{
ly[max(cnt1-1,0ll)].r=max(ly[max(cnt1-1,0ll)].r,mo[i].r);
}
}
if(n==1)
{
cout<<1<<endl;
}
else if(cnt1==0)
cout<<2<<endl;
else
cout<<quickpowmod(2,cnt1-1,998244353)<<endl;
return 0;
}