Educational Codeforces Round 122(Rated for Div. 2)
A-Div. 7
有\(t\)组样例,每个样例给你一个正整数\(n\),要求你改变最少数量的数位使得它没有前导\(0\)且能被\(7\)整除。每组输出任何一个可能的答案即可。\((1\leq t\leq990,10\leq n\leq999)\)
思路
只要改个位数应该就可以了吧。
代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
int _;
scanf("%d",&_);
while(_--)
{
int n;
scanf("%d",&n);
if(n%7==0)printf("%d\n",n);
else
{
int mod=n%7;
if(n%10>=mod)printf("%d\n",n-mod);
else printf("%d\n",n+7-mod);
}
}
return 0;
}
B-Minority
有\(t\)组样例,每个样例给你一个“\(01\)”串\(s\),你只能选取一个区间,然后删掉个数少的字符。每组问最多能删掉多少字符。\((1\leq t\leq10^4,\mid s\mid\leq2\cdot10^5)\)
思路
考虑全选,然后能删的一定是最多的,但是如果两个一样,那就减掉边上的一个就好了。
代码
#include<bits/stdc++.h>
using namespace std;
char s[1000005];
int main()
{
int _;
scanf("%d",&_);
while(_--)
{
scanf("%s",s+1);
int n=strlen(s+1);
int num1=0,num0=0;
for(int i=1;i<=n;i++)
{
if(s[i]=='1')num1++;
else num0++;
}
if(num1==num0)printf("%d\n",num1-1);
else printf("%d\n",min(num1,num0));
}
return 0;
}
C-Kill the Monster
有\(t\)组样例,每个样例给你\(h_c,d_c,h_m,d_m\),分别代表自己的血量、攻击力和怪兽的血量与攻击力。然后你有\(k\)次加倍的机会,每次加倍你都能选择使自己的攻击力增加\(w\)或者使自己的血量增加\(a\)。每组样例问你能否打败怪兽。\((1\leq t\leq5\cdot10^4)\)\((1\leq h_c\leq10^{15},1\leq d_c\leq10^9,1\leq h_m\leq10^{15},1\leq d_m\leq10^9)\)\((0\leq k\leq2\cdot10^5,0\leq w\leq10^4,0\leq a\leq10^{10})\)
思路
因为能加强,那肯定要么加血要么加攻击力,所以\(for\)一遍\(k\)就能结束了。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int _;
scanf("%d",&_);
while(_--)
{
ll hc,dc,hm,dm;
scanf("%lld%lld%lld%lld",&hc,&dc,&hm,&dm);
ll k,w,a;
scanf("%lld%lld%lld",&k,&w,&a);
bool ck=0;
for(int i=0;i<=k;i++)
{
if(hm/(dc+i*w)+(bool)(hm%(dc+i*w))<=(hc+(k-i)*a)/dm+(bool)((hc+(k-i)*a)%dm)){ck=1;break;}
}
if(ck)printf("YES\n");
else printf("NO\n");
}
return 0;
}
D-Make Them Equal
有t组样例,每个样例有两个数组\(b_1,b_2,…,b_n\)和\(c_1,c_2,...,c_n\),然后你还有一个数组\(a_1,a_2,...,a_n\),初值为\(1\)。现在你能进行\(k\)次操作,每次操作你能任选两个正整数\(i\)和\(x\),然后把\(a_i\)变成\(a_i+⌊\frac{a_i}{x}⌋\),如果\(a_i\)等于\(b_i\),你就能得到值\(c_i\)的硬币。问每组询问最多能得到多少价值硬币。\((1\leq t\leq100,1\leq n\leq10^3,0\leq k\leq10^6,1\leq b_i\leq10^3,1\leq c_i\leq10^6)\)
思路
首先想法当然是背包,但是\(1e9\)当然是冲不过\(1\)秒的,但是这道题很良心的给了两秒。然后来想一想如果只给一秒要怎么做。打个表能发现把\(1\)改成其他数最多只需要\(13\)步,那么当\(k\)大于\(13*n\)时答案就是\(\displaystyle\sum_{i=1}^{n}c_i\)了,反之,就可以来一个背包以\(1e3*1e4\)的复杂度轻松过掉了。
代码1
#include<bits/stdc++.h>
using namespace std;
int b[1005],c[1005];
struct node
{
int a,s;
};
queue<node>q;
int vis[1005];
int stp[1005];
int dp[1000020];
int main()
{
q.push({1,0});
vis[1]=1;
stp[1]=0;
while(!q.empty())
{
auto p=q.front();
q.pop();
int a=p.a,s=p.s;
for(int i=1;i<=a;i++)
{
int x=a+a/i;
if(x<=1000&&!vis[x])
{
q.push({x,s+1});
vis[x]=1;
stp[x]=s+1;
}
}
}
int _;
scanf("%d",&_);
while(_--)
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
b[i]=stp[b[i]];
}
for(int i=1;i<=n;i++)scanf("%d",&c[i]);
for(int i=1;i<=n;i++)
for(int j=1000000;j>=0;j--)
if(dp[j]||j==0)
dp[j+b[i]]=max(dp[j+b[i]],dp[j]+c[i]);
int ans=0;
for(int i=0;i<=k;i++)ans=max(ans,dp[i]);
printf("%d\n",ans);
if(_)
for(int i=0;i<=1000000;i++)
dp[i]=0;
}
return 0;
}
代码2
#include<bits/stdc++.h>
using namespace std;
int b[1005],c[1005];
struct node
{
int a,s;
};
queue<node>q;
int vis[1005];
int stp[1005];
int dp[1005][13020];
int main()
{
q.push({1,0});
vis[1]=1;
stp[1]=0;
while(!q.empty())
{
auto p=q.front();
q.pop();
int a=p.a,s=p.s;
for(int i=1;i<=a;i++)
{
int x=a+a/i;
if(x<=1000&&!vis[x])
{
q.push({x,s+1});
vis[x]=1;
stp[x]=s+1;
}
}
}
int _;
scanf("%d",&_);
while(_--)
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
b[i]=stp[b[i]];
}
int sum=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&c[i]);
sum+=c[i];
}
if(k>13*n){printf("%d\n",sum);continue;}
for(int i=1;i<=n;i++)
{
for(int j=0;j<=13*n;j++)
{
if(dp[i-1][j])
{
dp[i][j]=max(dp[i][j],dp[i-1][j]);
dp[i][j+b[i]]=max(dp[i][j+b[i]],dp[i-1][j]+c[i]);
}
}
dp[i][b[i]]=max(dp[i][b[i]],dp[i-1][0]+c[i]);
}
int ans=0;
for(int i=0;i<=k;i++)ans=max(ans,dp[n][i]);
printf("%d\n",ans);
if(_)
for(int i=1;i<=n;i++)
for(int j=0;j<=13*n;j++)
dp[i][j]=0;
}
return 0;
}
E-Spanning Tree Queries
给你一个\(n\)个点,\(m\)条边(可能有重边),且有边权的无向图,然后有\(k\)组询问,每次询问会给你一个\(x\),让你找到一种生成树,边权为\(w_1,w_2,...,w_{n-1}\),它的花费为\(\displaystyle\sum_{i=1}^{n-1}\mid w_i-x\mid\),答案为最小的花费。前p个询问给的数字为\(q_1,q_2,...,q_p\),对于第\(p+1\)到\(k\)次询问,\(q_j=(q_{j-1}\cdot a+b)\ mod\ c\)。最后输出所有答案的异或和。\((2\leq n\leq 50,n-1\leq m\leq300,0\leq w_i\leq10^8,1\leq p\leq10^5,p\leq k\leq10^7)\)\((0\leq a,b\leq10^8,1\leq c\leq10^8,0\leq q_j<c)\)
思路
简单讲一下思路。很容易就能想到\(kruskal\),但是每次又要重新排序,应该会\(t\)。但是我们可以想一下更改\(x\)对排序的影响,也就是对于\(w_a\)和\(w_b\),当\(x\)从小于\(\frac{w_a+w_b}{2}\)到大于\(\frac{w_a+w_b}{2}\)时\(w_a\)和\(w_b\)得交换一个位置。而所有排序的情况只有\(m^2\)种,所以很好预处理,然后对于每一个\(x\),便能得到对应的答案。