感想
我好菜啊,只能做出前三题……
以后再也不会打yutaka1999的比赛了……人神题目也神……
这一场……打得我……如果以我实力的话只能作出AC两题,B还是wzy教我的(%%%)
A - Digits Sum
题目大意
给定一个数,求正整数使得且 各位数字之和最小,输出最小的各位数字之和。
思路
显然不进位的加是最优的,尽量减少进位的次数,如果则答案为(必须进一次位),否则答案就为的各位数字相加。
代码
#include <cstdio>
int n;
int main()
{
scanf("%d",&n);
int sum=0;
while(n)
{
sum+=n%10;
n/=10;
}
if(sum==1)
{
sum=10;
}
printf("%d\n",sum);
return 0;
}
B - RGB Coloring
题目大意
给一张个格子的纸,不允许旋转和轴对称翻转,现在规定,红色的权值为,蓝色的权值为,绿色的权值为,不涂色权值为,要求给纸涂色使得这张纸的权值之和为,求涂色方案数%998244353。
(然而原题为啥是……)
思路
枚举红色的个数,可以得到蓝色的个数,然后分别乱填红色和蓝色,红色和蓝色都涂过的格子就是绿色。
代码
#include <cstdio>
const int mo=998244353;
const int maxn=300000;
int n,a,b,ans,fac[maxn+10],ifac[maxn+10];
long long k;
int c(int a,int b)
{
return 1ll*fac[a]*ifac[b]%mo*ifac[a-b]%mo;
}
int main()
{
scanf("%d%d%d%lld",&n,&a,&b,&k);
fac[0]=1;
for(int i=1; i<=n; ++i)
{
fac[i]=1ll*fac[i-1]*i%mo;
}
ifac[0]=ifac[1]=1;
for(int i=2; i<=n; ++i)
{
ifac[i]=1ll*(mo-mo/i)*ifac[mo%i]%mo;
}
for(int i=2; i<=n; ++i)
{
ifac[i]=1ll*ifac[i]*ifac[i-1]%mo;
}
for(int i=0; i<=n; ++i)
{
if((k-1ll*a*i)%b)
{
continue;
}
long long cntb=(k-1ll*a*i)/b;
if((cntb>n)||(cntb<0))
{
continue;
}
ans=ans+1ll*c(n,i)*c(n,cntb)%mo;
if(ans>=mo)
{
ans-=mo;
}
}
printf("%d\n",ans);
return 0;
}
C - Interval Game
题目大意
Alice和Bob在玩一个游戏,初始时Bob在数轴原点,Alice手上有条线段,每次进行操作:
- Alice选择一条之前没有选择过的线段;
- Bob走到线段上任意一点;
最后Bob回到数轴原点。
令Bob走过的距离为,Alice想要尽量大,Bob想要尽量小,求最终是多少。
思路
这道题很容易想到一个贪心方案:
按线段右端点从小到大排序,令排序后的线段序列为;
按线段左端点从大到小排序,令排序后的线段序列为。
每次比较 右端点最小的那条线段到当前点的距离 与 左端点最大的那条线段到当前点的距离,并走向更大的那个。
但是如果开始时两边到坐标原点的距离一样,则两边都尝试一遍。
代码
#include <cstdio>
#include <cmath>
#include <algorithm>
const int maxn=100000;
int read()
{
int x=0,f=1;
char ch=getchar();
while((ch<'0')||(ch>'9'))
{
if(ch=='-')
{
f=-f;
}
ch=getchar();
}
while((ch>='0')&&(ch<='9'))
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
struct seg
{
int l,r,flag;
};
seg s[maxn+10];
bool cmpl(int a,int b)
{
return s[a].l>s[b].l;
}
bool cmpr(int a,int b)
{
return s[a].r<s[b].r;
}
int n,a[maxn+10],b[maxn+10];
long long rans;
inline int dist(int now,int to)
{
if(now<s[to].l)
{
return s[to].l-now;
}
else if(now>s[to].r)
{
return now-s[to].r;
}
else
{
return 0;
}
}
inline int getnow(int now,int to)
{
if(now<s[to].l)
{
return s[to].l;
}
else if(now>s[to].r)
{
return s[to].r;
}
else
{
return now;
}
}
int main()
{
n=read();
for(int i=1; i<=n; ++i)
{
s[i].l=read();
s[i].r=read();
a[i]=b[i]=i;
}
std::sort(a+1,a+n+1,cmpl);
std::sort(b+1,b+n+1,cmpr);
int left=1,right=1,now=0;
long long ans=0;
s[a[1]].flag=1;
ans+=dist(now,a[1]);
now=getnow(now,a[1]);
for(int i=1; i<n; ++i)
{
while(s[a[left]].flag)
{
++left;
}
while(s[b[right]].flag)
{
++right;
}
if(dist(now,a[left])>dist(now,b[right]))
{
s[a[left]].flag=1;
ans+=dist(now,a[left]);
now=getnow(now,a[left]);
}
else
{
s[b[right]].flag=1;
ans+=dist(now,b[right]);
now=getnow(now,b[right]);
}
}
for(int i=1; i<=n; ++i)
{
s[i].flag=0;
}
rans=ans+abs(now);
left=right=1;
now=ans=0;
s[b[1]].flag=1;
ans+=dist(now,b[1]);
now=getnow(now,b[1]);
for(int i=1; i<n; ++i)
{
while(s[a[left]].flag)
{
++left;
}
while(s[b[right]].flag)
{
++right;
}
if(dist(now,a[left])>dist(now,b[right]))
{
s[a[left]].flag=1;
ans+=dist(now,a[left]);
now=getnow(now,a[left]);
}
else
{
s[b[right]].flag=1;
ans+=dist(now,b[right]);
now=getnow(now,b[right]);
}
}
printf("%lld\n",std::max(ans+abs(now),rans));
return 0;
}