B. Make it Divisible by 25(思维)
题意:
给出一个数n,问最少去掉多少数位,能够使得所得到的新数为25的倍数?
(n≤1e18)
思路:
一个数为25的倍数,那么这样的数有一定的特点:
末尾为:25 或 50 或 75 或 x*100。
所以只需要找到2的位置和5的位置,将其中间的和5后面的所有位置去掉,就能保证所得到的新数是25的倍数了。50和75同理。
而所给的数 n 是没有前导0的,所以最后一种x*100的情况,只需要判断两个0就行了。找到两个0的位置,中间和第二个0后面的所有位置去掉。
数位长度很小,所以二重循环遍历找就行了。
Code:
const int N = 200010, mod = 1e9+7;
int T, n, m;
string a;
int main(){
Ios;
cin>>T;
while(T--)
{
cin>>a;
int n=a.size();
a=" "+a;
int ans=1e9;
for(int i=1;i<=n;i++)
{
if(a[i]=='2')
{
for(int j=i+1;j<=n;j++)
{
if(a[j]=='5'){
ans=min(ans,j-i-1+n-j);
}
}
}
if(a[i]=='5')
{
for(int j=i+1;j<=n;j++)
{
if(a[j]=='0'){
ans=min(ans,j-i-1+n-j);
}
}
}
if(a[i]=='7')
{
for(int j=i+1;j<=n;j++)
{
if(a[j]=='5'){
ans=min(ans,j-i-1+n-j);
}
}
}
if(a[i]=='0')
{
for(int j=i+1;j<=n;j++)
{
if(a[j]=='0'){
ans=min(ans,j-i-1+n-j);
}
}
}
}
cout<<ans<<endl;
}
return 0;
}
C. Save More Mice(贪心,模拟)
题意:
在一维坐标中,有一只猫在原点位置,有一个洞口在 k 位置(k≥2),原点和k位置之间,有n个老鼠。
现在每一秒,只能有一只老鼠移动一格,猫移动一格。猫会吃掉在所在位置上的老鼠,而老鼠移动到洞口 k 位置之后,便是安全的了。
问,最多能够有多少只老鼠是安全的?
思路:
因为所有老鼠所在位置在猫和洞口位置之间,而每次只能一只老鼠移动一格,为了使得安全老鼠尽量多,只能让距离洞口最近的那只老鼠先进洞。
按位置从后往前遍历所有老鼠:
- 如果当前老鼠的位置大于前面老鼠浪费的时间,因为每次猫和老鼠轮流走一格,则说明这个老鼠是可以移动到洞口的。
这个老鼠所浪费的时间为原来位置到洞口的位置之差。 - 否则的话,当前及前面所有的老鼠都跑不掉。
Code:
const int N = 400010, mod = 1e9+7;
int T, n, m, a[N];
int main(){
Ios;
cin>>T;
while(T--)
{
int k;
cin>>k>>n;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
ll t=0,cnt=0;
for(int i=n;i>=1;i--)
{
if(a[i]>t) t+=k-a[i],cnt++;
}
cout<<cnt<<endl;
}
return 0;
}
D1. All are Same(思维)
题意:
给出长度为 n 的数列,找出最大的 k,使得进行若干次下述操作,所有位置上的元素相同:选定一个位置 i i i,将此位置上的数 a[i] -= k
。 ( n ≤ 40 , − 1 e 6 ≤ a [ i ] ≤ 1 e 6 ) (n≤40, -1e6≤a[i]≤1e6) (n≤40,−1e6≤a[i]≤1e6)
如果 k 可以任意大,输出 -1。
思路:
因为改变一个位置只能减不能加,而把原来最小元素也 - k 的话,为了使所有元素相同,其他所有位置都要多减一个 k。
所以,最终所有位置上的值只能为原来所有元素中的最小值mina。
而满足条件的 k,必须让原来值减若干次之后,正好变成最小元素mina。
所以 k 要使所有位置的元素满足 (a[i]-mina)%k == 0
。
k 最大不超过所有数的最大绝对值*2
,从大到小遍历所有的 k,看是否满足。
还需要考虑输出-1的情况,什么情况下 k 可以随意大呢?
所有数大小相同的时候,可以进行任意次操作,并且每次操作减任意值。
Code:
const int N = 200010, mod = 1e9+7;
int T, n, m, a[N];
int main(){
Ios;
cin>>T;
while(T--)
{
cin>>n;
int mina=1e9,maxa=-10,ff=0;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]<mina) mina=a[i];
if(abs(a[i])>maxa) maxa=abs(a[i]);
if(i>1&&a[i]!=a[i-1]) ff=1;
}
if(!ff){
cout<<-1<<endl;
continue;
}
for(int i=2*maxa;i;i--)
{
bool flag=0;
for(int j=1;j<=n;j++){
if((a[j]-mina)%i!=0){
flag=1;break;
}
}
if(!flag){
cout<<i<<endl;
break;
}
}
}
return 0;
}
突然看到另一种做法,不需要暴力枚举所有 k:
求出所有数和 mina 之差,取所有差值的最大公约数为 k。
因为 k 是要被所有差值整除的,并且还要最大,那刚好是最大公约数!
这种做法时间复杂度就很优了。
E. Gardener and Tree(拓扑图)
题意:
对于一棵无根树,每次操作将这棵树的所有叶子节点删去。
问,m次操作后,最终剩余的节点个数?
思路:
对于分层操作,原来记的做法复杂度为O(n^2),现在这个做法复杂度为O(n+m)。
首先将入度为1的节点存入vector。
每次遍历vector中的所有节点,将与其相连的节点入度-1。如果删除入度之后,一节点的入度为1了,说明这个点是下一层需要删除的点,存入新一vector中,下一层用。
因为每个点只会遍历到一次,每条边最多用两次,所以复杂度O(N+M)。
所以之后遇到分级的题,用这种做法。
Code:
const int N = 800010;
int T, n, m, a[N];
int e[N],ne[N],h[N],idx;
int ru[N],f[N];
void add(int x,int y){
e[idx]=y,ne[idx]=h[x],h[x]=idx++;
}
void tpsort()
{
vector<int> v;
for(int i=1;i<=n;i++) if(ru[i]==1) v.push_back(i);
int cnt=0;
while(v.size())
{
cnt++;
vector<int> v1;
for(int i=0;i<v.size();i++)
{
int x=v[i];
f[x]=cnt;
for(int j=h[x];j!=-1;j=ne[j])
{
int tx=e[j];
ru[tx]--;
if(ru[tx]==1) v1.push_back(tx);
}
}
v=v1;
}
}
int main(){
Ios;
cin>>T;
while(T--)
{
cin>>n>>m;
for(int i=1;i<=n;i++) ru[i]=0,f[i]=0,h[i]=-1;
for(int i=1;i<n;i++)
{
int x,y;
cin>>x>>y;
add(x,y);
add(y,x);
ru[x]++,ru[y]++;
}
tpsort();
int cnt=0;
for(int i=1;i<=n;i++) if(f[i]>m) cnt++;
cout<<cnt<<endl;
}
return 0;
}
第二天更…
发现 这位大佬 还有另外一总做法:
记录每个点的层级数。对于新更新到点 t x tx tx 的层级,为更新这个点 x x x 的层级 + 1 +1 +1。
直接跑拓扑排序就行了。
Code:
const int N = 800010, mod = 1e9+7;
int T, n, m, a[N];
int ru[N],f[N];
int e[N],ne[N],h[N],idx;
void add(int x,int y){
e[idx]=y,ne[idx]=h[x],h[x]=idx++;
}
void tpsort()
{
queue<int> que;
for(int i=1;i<=n;i++){
if(ru[i]==1) que.push(i),f[i]=1;
}
while(que.size())
{
int x=que.front();que.pop();
for(int i=h[x];i!=-1;i=ne[i])
{
int tx=e[i];
ru[tx]--;
if(ru[tx]==1)
{
que.push(tx);
f[tx]=f[x]+1;
}
}
}
}
int main(){
Ios;
int T;
cin>>T;
while(T--)
{
cin>>n>>m;
for(int i=1;i<=n;i++) h[i]=-1,f[i]=0,ru[i]=0;
for(int i=1;i<n;i++)
{
int x,y;cin>>x>>y;
add(x,y);add(y,x);
ru[x]++,ru[y]++;
}
tpsort();
int cnt=0;
for(int i=1;i<=n;i++) if(f[i]>m) cnt++;
cout<<cnt<<endl;
}
return 0;
}
哪里有问题或者不明白的地方欢迎留言评论~