AtCoder Beginner Contest 363
AtCoder Beginner Contest 363
A - Piling Up
每100分显示一个
^
。现在已知分数,问想要多显示一个^
需要再得多少分。
模拟题,显示\(i\)个^
的最小分数是\(100\times i\),而当前的^
是\([\frac{R}{100}]\),\(R\)是当前的分数。
所以答案就是\(([\frac{R}{100}]+1)\times 100-R\)
#include<iostream>
#include<cstdio>
using namespace std;
int R;
int main()
{
cin>>R;
int display=R/100;
cout<<(display+1)*100-R<<endl;
return 0;
}
B - Japanese Cursed Doll
有\(n\)个数,第\(i\)个是\(L_i\),每个数在每个时刻都会增长\(1\)。问在哪个时刻第一次有\(P\)个数会大于等于\(T\)。如果初始时就满足条件,则输出\(0\)。
将\(L\)从小往大排序,那么只需要第\(n-P+1\)大的数满足条件即可,假设这个数是\(a\)。因此,只需要计算\(T-a\)即可。注意,如果这个数是负数,意味着初始时就满足条件,此时要输出\(0\)。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAX=105;
int n,T,P;
int L[MAX];
int main()
{
cin>>n>>T>>P;
for(int i=1;i<=n;++i)cin>>L[i];
sort(&L[1],&L[n+1]);
int l=L[n-P+1];
int ans=max(0,T-l);
cout<<ans<<endl;
return 0;
}
C - Avoid K Palindrome 2
有一个长度为\(n\)的字符串\(S\)。问有多少个字符串满足:1、通过\(S\)重排列得到;2、没有一个长度为\(K\)的回文子串。
注意数据范围,完全可以依次枚举每一个排列,可以使用next_permutation
函数。接着暴力判断是否拥有回文子串即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,k,ans;
char c[15];
int main()
{
scanf("%d%d",&n,&k);
scanf("%s",c+1);
sort(&c[1],&c[n+1]);
do
{
bool flag=true;
for(int i=1;i+k-1<=n;++i)
{
bool f=true;
for(int j=0;j<k;++j)
if(c[i+j]!=c[i+k-1-j])
f=false;
if(f)flag=false;
}
if(flag)++ans;
}while(next_permutation(&c[1],&c[n+1]));
printf("%d\n",ans);
return 0;
}
D - Palindromic Number
求第\(k\)大的回文数。
回文数只需要考虑前一半就可以构造。
枚举长度,首先计算出答案回文数的长度。通过枚举和减法可以计算出是当前长度下第\(k\)大的回文数。
而前一半就是顺序的,第\(k\)大就是当前长度的数的第\(k\)大,这个很好求。
接下来只需要构成回文,直接输出即可。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
long long N;
long long fpow(long long a,long long b)
{
long long ret=1;
while(b)
{
if(b&1)ret*=a;
a*=a;
b>>=1;
}
return ret;
}
int a[1000];
int main()
{
cin>>N;
N-=1;
if(N<10)
{
printf("%lld\n",N);
return 0;
}
int l=1;
while(true)
{
int t=(l+1)>>1;
long long m=9ll*fpow(10,t-1);
if(N>m)N-=m;
else break;
++l;
}
int t=(l+1)>>1;
int len=0;
N-=1;
while(N)a[++len]=N%10,N/=10;
a[t]+=1;
for(int i=t;i;--i)printf("%d",a[i]);
for(int i=1+(l&1);i<=t;++i)printf("%d",a[i]);
puts("");
return 0;
}
E - Sinking Land
有一个\(H\times W\)的岛屿,周围被大海环绕。
这个岛屿可以被分成\(H\times W\)个\(1\times 1\)的方块,\((i,j)\)方块的高度是\(A_{i,j}\)。
第\(i\)时刻,海平面高度是\(i\),如果一个方块与海相邻且高度不超过海平面,则会被淹没。
给定\(Y\),回答\(1-Y\)时刻,每个时刻还未被淹没的方块数量。
把所有和海面相邻的方块给丢进队列里面BFS,每次暴力枚举时间。这样子时间复杂度是\(O(Y\times 2(H+W))\),复杂度的数量级其实是没有问题的,但是常数比较大,可能无法通过。
用优先队列优化上述过程,每次取最接近被淹没的方块出来,这样子可以优化掉时间这一维度,可以做到\(O(HW)\)。
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<vector>
using namespace std;
struct Node
{
int x,y,t;
bool operator<(const Node &a)const{
return t>a.t;
}
};
priority_queue<Node> Q;
const int MAX=1005;
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int d[4][2]={0,1,0,-1,1,0,-1,0};
int H,W,Y,A[MAX][MAX];
bool vis[MAX][MAX];
int ans[100100];
int main()
{
H=read();W=read();Y=read();
for(int i=1;i<=H;++i)
for(int j=1;j<=W;++j)
A[i][j]=read();
for(int i=1;i<=H;++i)
for(int j=1;j<=W;++j)
vis[i][j]=false;
for(int i=1;i<=H;++i)
for(int j=1;j<=W;++j)
if(i==1||j==1||i==H||j==W)
vis[i][j]=true,Q.push((Node){i,j,A[i][j]});
int T=0;
while(!Q.empty())
{
Node now=Q.top();
Q.pop();
int x=now.x,y=now.y,t=now.t;
T=max(T,t);
ans[T]++;
for(int i=0;i<4;++i)
{
int nx=x+d[i][0];
int ny=y+d[i][1];
if(nx>=1&&nx<=H&&ny>=1&&ny<=W)
if(!vis[nx][ny])
{
vis[nx][ny]=true;
Q.push((Node){nx,ny,A[nx][ny]});
}
}
}
for(int i=1;i<=Y;++i)ans[i]+=ans[i-1];
for(int i=1;i<=Y;++i)printf("%d\n",H*W-ans[i]);
return 0;
}
F - Palindromic Expression
给定一个数,问是否存在一个因数分解的方法,使得分解的结果可以列为一个只包含数字
1-9
和*
回文串。
暴力搜索!
如果当前的数字\(N\)自己本身就是一个不含零的回文数,那么直接返回。
否则的话,需要找到一对回文质因数,直接暴力枚举因数,检查是否有回文因数,如果有,那么递归处理即可。
#include<iostream>
#include<cmath>
#include<algorithm>
#include<string>
using namespace std;
#define ll long long
ll N;
string dfs(ll N)
{
string s=to_string(N);
string s_rev=s;
reverse(s_rev.begin(),s_rev.end());
int l=s.length();
bool zero_flag=false;
for(int i=0;i<l;++i)if(s[i]=='0')zero_flag=true;
if(!zero_flag&&s==s_rev)return s;
for(int i=2,l=sqrt(N);i<=l;++i)
if(N%i==0)
{
bool flag=true;
int t=i,j=0;
while(t)
{
if(t%10==0)flag=false;
t/=10;
}
t=i;
if(!flag)continue;
while(t)j=j*10+t%10,t/=10;
if((N/i)%j==0)
{
string ret=dfs(N/i/j);
if(ret!="")
return to_string(i)+"*"+ret+"*"+to_string(j);
}
}
return "";
}
int main()
{
cin>>N;
string ret=dfs(N);
if(ret!="")cout<<ret<<endl;
else cout<<-1<<endl;
return 0;
}
G - Dynamic Scheduling
给定两个长度为\(n\)的序列D和P。
有\(Q\)个操作,每个操作形如c x y
,将\(D_c\)改为\(x\),将\(P_c\)改为\(y\)。
每次修改完成之后,回答如下问题的答案:
有\(n\)个任务,每天可以做一个任务,如果一个任务在\(D_i\)天前被解决,则可以获得奖励\(P_i\)。问可以得到的最大奖励。
模拟费用流。用线段树维护区间堆进行贪心。