本次我们打星参赛,rk95,在银牌区内,希望济南站能发挥出应有的水平拿到银牌。
按开题顺序给上思路与代码。
队友1秒签,我也不知道发生了甚么事情。
#include
using namespace std;
int t,n,m,a[100005],b[100005],pa,pb,c,ma;
int main()
{
cin>>t;
while(t--){
cin>>n>>m;
for(int i=0;i<n;i++){
cin>>a[i];
}
for(int i=0;i<m;i++){
cin>>b[i];
}
sort(a,a+n);
sort(b,b+m);
pa=c=ma=0;
for(int i=0;i<m;i++){
c=0;
while(a[pa]<b[i]&&pa<n){
c++;
pa++;
}
ma=max(ma,c);
while(a[pa]<=b[i]&&pa<n){
pa++;
}
}
ma=max(n-pa,ma);
if(ma==0){
cout <<"Impossible" << endl;
}else{
cout <<ma << endl;
}
}
return 0;
}
队友2跟我一起看的。看着像个很厉害的题,实际上很假。
不难发现对于任意的正整数x,x+1,x与x+1互质,x+1与x互质。
此外,1与任何数的gcd都为1。
这样就得解了,讨论k,当k为奇数时让1保持不变,1后面的k-1个数两两调换位置,如
给出n=5,k=3,5个数为:
1,2,3,4,5
则变为
1,3,2,5,4
当k为偶数时,则直接让前k个数两两调换位置。
代码其实写的挺丑的,好在1A了。
#include
using namespace std;
int n, k;
int main()
{
ios::sync_with_stdio(false);
cin >> n >> k;
if(k==0)cout << -1 << endl;
else {
if(k&1){
cout << 1;
for(int i = 2; i < k; i+=2){
cout << ' ' << i+1 << ' ' << i;
}
for(int i = k+1; i <= n; ++i)cout << ' ' << i;
}
else {
for(int i = 1; i <= k; i+=2){
if(i != n)cout << i+1 << ' ' << i << ' ';
else cout << i+1 << ' ' << i;
}
for(int i = k+1; i <= n; i++){
if(i != n)cout << i << ' ';
else cout << i;
}
}
}
return 0;
}
题意是要求至少一次完美施放所消耗的时间的期望。
我们假设做k个烟火,然后施放一次,那么这一组施放至少出现一次完美释放的概率就是1-(10000-p)^k,假设这个值为t,那么至少一次完美施放所消耗的时间就可以表示为(k*n+m)*1/t。
我们要找到一个整数k,使得上面这个式子的值尽可能小。
不难发现,实际上这个式子与k的关系是先递减后递增,存在一个极小值,找到这个极小值即可。
队友1写了个类似于2分的代码解决了,主要是中间判了下当前位置是递减还是递增。
#include
using namespace std;
typedef long long ll;
ll t,n,m,p,pl,kr;
double la ;
double getE(ll k){
return (k*1.0*n+m)/(1-pow((10000.0-p)/10000,k));
}
ll f(ll l,ll r){
if(l>=r-2){
return l;
}
ll mid=(l+r)/2;
if(getE(mid)>getE(mid+1)){
return f(mid,r);
}else{
return f(l,mid+1);
}
}
int main()
{
cin>>t;
while(t--){
cin>>n>>m>>p;
la=getE(1);
pl=2;
while(getE(pl)>=la){
la=getE(pl);
la*=2;
}
kr=f(1,la);
printf("%.10lf\n",min(min(getE(kr),getE(kr+1)),getE(kr+2)));
}
return 0;
}
不难发现只当炸弹在终点,或只能沿一个方向走且炸弹在路径上时才会无解,这些情况可以特判处理一下,然后就是找一条路径规避掉炸弹点。
写起来细节很多,wa了两发后过的。
#include
using namespace std;
int t,mx,my,tx,ty,u,d,l,r;
string str;
void pc(char c,int n){
while(n--){
putchar(c);
}
}
int main()
{
cin>>t;
while(t--){
cin>>mx>>my>>str;
u=d=l=r=0;
for(int i=0;str[i];i++){
switch(str[i]){
case 'U':u++;break;
case 'D':d++;break;
case 'L':l++;break;
case 'R':r++;break;
}
}
ty=u-d;tx=r-l;
if(ty!=my&&0!=mx){
pc('U',u);pc('D',d);pc('L',l);pc('R',r);
}else if(tx!=mx&&0!=my){
pc('L',l);pc('R',r);pc('U',u);pc('D',d);
}else if((ty==my&&tx==mx)||(0==my&&0==mx)){
cout<<"Impossible";
}else if(tx==0&&ty==0){
if(mx>0){
pc('L',l);pc('R',r);
}else{
pc('R',r);pc('L',l);
}
if(my>0){
pc('D',d);pc('U',u);
}else{
pc('U',u);pc('D',d);
}
}else if(tx==0){
if(l!=0){
pc('L',l);pc('U',u);pc('D',d);pc('R',r);
}else if(my>ty&&my>0){
pc('D',d);pc('U',u);
}else if(my<ty&&my<0){
pc('U',u);pc('D',d);
}else{
cout<<"Impossible";
}
}else{
if(u!=0){
pc('U',u);pc('L',l);pc('R',r);pc('D',d);
}else if(mx>tx&&mx>0){
pc('L',l);pc('R',r);
}else if(mx<tx&&mx<0){
pc('R',r);pc('L',l);
}else{
cout<<"Impossible";
}
}
cout<<endl;
}
return 0;
}
另外给一些构造的样例,也许能帮你找到你的wa点。
1 0
LLRR
-1 0
LLRR
0 1
UUDD
0 -1
UUDD
1 0
RRUD
-1 0
LLUD
0 1
LRUU
0 -1
LRDD
0 1
LRUD
队友2以为是个容斥,感觉不可做。最后发现了可能是打表,但错误估计了打表范围,时间也不够了。
突破口在于当矩阵足够大时不存在找不到目标矩形的矩阵。
根据榜盲猜贪心,写了两个小时,发现样例过不了后甚至想出了反向加点取min的操作,不出意外的wa了。
实际上是一道比较常规的树形dp,但我们没人会写,挺可惜的。
dp的核心有两个点,一个是枚举时只枚举到子树大小,就是子树中删除了多少个点,然后结合当前顶点删没删来更新当前节点的答案;第二个点是当前顶点删不删减少的贡献并不在当前顶点计算,只是标记一下,用以在枚举子节点时更新状态。
dp从0开始,0是虚拟节点,在这里更新1号节点删与不删增加的贡献。
#include
typedef long long ll;
using namespace std;
const int maxn = 2010;
ll dp[maxn][maxn][2];
ll hp[maxn];
ll sum[maxn];
ll son[maxn];
vector<int> g[maxn];
ll tmp[maxn][2],t1[maxn][2];
int f[maxn];
void dfs(int u)
{
son[u] = 1;
vector<pair<int,int> > vec;
for(auto v : g[u])
{
dfs(v);
vec.push_back({son[v],v});
}
//sort(vec.begin(),vec.end(),greater>() );
for(auto p : vec)
{
int v = p.second;
memset(tmp,0,sizeof(tmp));
for(int j = 0;j <= son[v];j++)
{
tmp[j][0] = max(tmp[j][0],dp[v][j][0]);
tmp[j][1] = max(tmp[j][1],dp[v][j][0]);
tmp[j+1][0] = max(tmp[j+1][0],dp[v][j][1]+sum[v]+((v>1)?hp[v]:0ll));
tmp[j+1][1] = max(tmp[j+1][1],dp[v][j][1]+sum[v]);
}
memset(t1,0,sizeof(t1));
for(int j = 0;j <= son[v];j++)
{
for(int k = 0;k <= son[u];k++){
t1[j+k][0] = max(t1[j+k][0],tmp[j][0]+dp[u][k][0]);
t1[j+k][1] = max(t1[j+k][1],tmp[j][1]+dp[u][k][1]);
}
}
son[u]+=son[v];
for(int j = 0;j <= son[u];j++)
{
dp[u][j][0] = t1[j][0];
dp[u][j][1] = t1[j][1];
}
}
}
void solve()
{
int n;
ll ans = 0;
cin >> n;
for(int i = 0;i <= n;i++) g[i].clear();
g[0].push_back(1);
for(int i = 2;i <= n;i++)
{
cin >> f[i];
g[f[i]].push_back(i);
}
for(int i = 1;i <= n;i++)
{
cin >> hp[i];
ans+=hp[i];
if(i>1) ans += hp[i];
sum[i] = hp[i];
}
for(int i = 2;i <= n;i++)
{
sum[f[i]]+=sum[i];
}
for(int i = 0;i <= n;i++)
{
memset(dp[i],0,sizeof(dp[i]));
}
dfs(0);
for(int i = 0;i <= n;i++)
{
if(i) cout << ' ';
cout << ans-max(dp[0][i][0],dp[0][i][1]);
}
cout << endl;
return;
}
int main()
{
int T;
ios::sync_with_stdio(false);
cin >> T;
while(T--)
{
solve();
}
return 0;
}