1.【LGR-150-Div.2】洛谷 8 月月赛 I & RiOI Round 2

【LGR-150-Div.2】洛谷 8 月月赛 I & RiOI Round 2

T1 P9496 「RiOI-2」hacker

100pts

题目描述

有两种操作,ACCEPTBOTH,均花费 1 代价。ACCEPTn 二进制 按位或 一个正整数。BOTHn 二进制 按位与 一个正整数。两种操作均可使用多次(或不用),请求出将 n 变为 m 最小的代价。

帮助:什么是按位与和按位或

  • 水题,但是一开始用 scanf 输入 longlong 没有用 "%lld" 然后 WA 了两个点。
    • nm 转化为二进制,用两个数组分别存起来,再枚举。
    • n 表示为 0b 表示为1,则进行ACCEPT操作。
    • m 表示为 1b 表示为0,则进行BOTH操作。
#include<bits/stdc++.h>
using namespace std;
long long int n,sum=0;
long long int x,y;
long long int a[100],b[100];
int main()
{
long long int i,j,m,t;
scanf("%lld",&t);
while(t--)
{
sum=0;
scanf("%lld%lld",&n,&m);//scanf输入long long需要 "%lld"
if(n==m)
{
printf("%d\n",0);
continue;
}
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
int cnt=0,res=0;
int cn=0,cm=0;
x=n,y=m;
while(x)
{
a[++cnt]=x%2;
x/=2;
}
while(y)
{
b[++res]=y%2;
y/=2;
}
for(i=1;i<=max(cnt,res);i++)
{
if(a[i]==1&&b[i]==0)cn=1;
if(a[i]==0&&b[i]==1)cm=1;
}
printf("%d\n",cn+cm);
}
}
  • 听机房大佬说,其实有一个 O(1) 算法,如果 m==n,就输出0,如果 (m|n)==m 或者 (m|n)==n 输出1,如果都不符合,输出 2
  • n 表示为 100010m 表示为 110010,此时使 n 按位或 m,结果为110010,等于m
  • n 表示为 10010m 表示为 110010,此时使 n 按位或 m,结果为110010,等于m
  • n 表示为 10110010m 表示为 110010,此时使 n 按位或 m,结果为10110010。等于n
  • n 表示为 110110m 表示为 110010,此时使 n 按位或 m,结果为110110,等于n
  • n 表示为 110101m 表示为 110010 时,此时使 n 按位或 m,结果为110111,不等于 n,也不等于 m,此时需要用两种操作。
  • 即当按位或后,若 mn 有不同的位,如有一位 n0m1。并且如果有一位 n1m0,也就是 (m|n) 不等于 m 也不等于 n。则需要进行两次操作。
#include<bits/stdc++.h>
int main()
{
long long int t,n,m;
scanf("%ld",&t);
while(t--)
{
scanf("%ld%ld",&n,&m);
if(n==m) printf("0\n");
else if((n|m)==m||(n|m)==n) printf("1\n");
//位运算优先级较低,需要用括号括起来。
else printf("2\n");
}
}

T2 P9497 「RiOI-2」weight

100pts

题目描述

给定一个 nn 列 的矩阵 a

q 组询问,每次给定一个 v,请将矩阵每一行任意重排(可以不重排),最大化最大值不小于 v(也就是说,至少有一个不小于 v 的数)的列数。请输出这个列数。

询问之间相互独立。换言之,每次询问前可以重新排列。

  • 还是水题,将二维矩阵压成一位数组,输入后再从大到小 sort 一遍,每次询问时,从 1n 中寻找第一个小于 v 的数,如果都大于等于 v 则,输出 n
    • 一开始没看懂题目,以为是把每行从大到小排列。没看到最大化每排的最大值。
    • 改过来之后,发现输出都是 0 ,但没想太多就交上去了,但是竟然 AC 了,才想起来电脑是32位,longlong 显示为0
#include<bits/stdc++.h>
using namespace std;
long long int n,q,a[1010001];
long long int maxx[1001];
bool cmp(long long int x,long long int y)
{
return x>y;
}
int main()
{
int i,j;
cin>>n>>q;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
scanf("%ld",&a[(i-1)*n+j]);
stable_sort(a+1,a+1+n*n,cmp);
for(i=1;i<=n;i++)maxx[i]=a[i];
long long int w;
for(i=1;i<=q;i++)
{
int flag=0;
scanf("%ld",&w);
for(j=1;j<=n;j++)
{
if(maxx[j]<w)
{
printf("%ld\n",j-1);
flag=1;
break;
}
}
if(!flag)printf("%ld\n",n);
}
}

T3 P9498 「RiOI-2」equals

100pts

题目描述

给定一棵 n 个结点,以 1 为根的树,定义一个结点的深度 di 表示它到根结点的简单路径上的结点个数。

你需要给每个结点黑白染色,满足黑色结点的深度和等于白色结点的深度和。设 ci={0,1} 分别代表编号为 i 的结点为黑色或白色,那么这即 ci=0di=ci=1di

若无解,仅输出一行一个整数 1

  • 一开始打算用邻接矩阵存边,但是...

数据规模与约定

Subtask 分值 n 特殊性质
0 5 20 /
1 15 500 /
2 20 5×103 /
3 10 / n 为偶数
4 5 / 树为菊花图(不保证根为菊花中心)
5 5 / 树为一条链(不保证根为链的端点)
6 40 / /

斜杠表示这一栏无特殊限制。

对于 100% 的数据,1n1061ui,vin,输入数据构成一棵树。

  • 由于1n106,所以改用链式前向星存边。
  • dfs 一遍得出深度,由于黑点、白点的深度和要相等,所以想到前几天做的分钱,于是用dp判断是否有解。
  • 但是如果有解需要输出点的状态,而本蒟蒻不会记录路径,因此放弃了dp
  • 放弃了dp,考虑爆搜,打搜索。因为爆搜超时,开始一分没骗到,然后剪枝得了85
    之后想到折半搜索,但是本蒟蒻只会折半,因此分了两个for循环,第一个从1循环到(n+1)/2
    第二个从(n+1)/2循环到n。(但应该不是正解)。然后AC了......

(出题人的数据怎么如此之氵,把爆搜都放过去了)...

测评记录

#include<bits/stdc++.h>
using namespace std;
long long int dep[6000001],vis[6000001];
long long int n,sum=0;
struct ee
{
int next,to;
}e[6000001];
int head[6000001],cnt=0;
void add(int u,int v)
{
e[++cnt]={head[u],v};
head[u]=cnt;
}
void dfs(int x)
{
int i;
vis[x]=1;
for(i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if(!vis[v])
dep[v]=dep[x]+1,dfs(v);
}
}
bool pd[6000001];
void search(int x,long long int s)
{
int i,j;
if(s==(sum/2))
{
for(j=1;j<=n;j++)
{
if(pd[j])printf("%d ",1);
else printf("%d ",0);
}
exit(0);
}
for(i=x;i<=(n+1)/2;++i)
{
if(!pd[i]&&s+dep[i]<=(sum/2))
{
pd[i]=1;
if(s+dep[i]==(sum/2))
{
for(j=1;j<=n;j++)
{
if(pd[j])printf("%d ",1);
else printf("%d ",0);
}
exit(0);
}
if(s+dep[i]<(sum/2))
search(i+1,s+dep[i]);
pd[i]=0;
}
}
for(i=(n+1)/2;i<=n;++i)
{
if(!pd[i]&&s+dep[i]<=(sum/2))
{
pd[i]=1;
if(s+dep[i]==(sum/2))
{
for(j=1;j<=n;j++)
{
if(pd[j])printf("%d ",1);
else printf("%d ",0);
}
exit(0);
}
if(s+dep[i]<(sum/2))
search(i+1,s+dep[i]);
pd[i]=0;
}
}
}
int main()
{
int i,j,m,x,y;
scanf("%d",&n);
for(i=1;i<n;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
dep[1]=1;
dfs(1);
for(i=1;i<=n;++i)sum+=dep[i];
if(sum%2==1)
{
printf("%d",-1);
return 0;
}
search(1,0);
printf("%d",-1);
}

T4 P9499 「RiOI-2」change

20pts

  • 本蒟蒻不会打,骗了20分。。。
posted @   minecraft114514  阅读(109)  评论(4编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示