G.做题
题意:
n
道
题
,
总
共
m
分
钟
n道题,总共m分钟
n道题,总共m分钟
每
道
题
需
要
花
a
i
分
钟
,
最
多
写
多
少
题
每道题需要花a_i分钟,最多写多少题
每道题需要花ai分钟,最多写多少题
题解:
排
序
,
每
次
写
时
间
最
小
的
题
,
计
算
一
下
能
写
多
少
道
就
可
以
排序,每次写时间最小的题,计算一下能写多少道就可以
排序,每次写时间最小的题,计算一下能写多少道就可以
注
意
数
据
范
围
,
要
用
l
l
注意数据范围,要用ll
注意数据范围,要用ll
AC代码
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=5e5+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
ll a[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
ll n,k;
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+1+n);
ll ans=0;
for(int i=1;i<=n;i++){
if(k>=a[i])ans++,k-=a[i];
if(k<=0)break;
}
cout<<ans;
return 0;
}
F.斗兽棋
题意:
e
l
e
p
h
a
n
t
−
>
t
i
g
e
r
−
>
c
a
t
−
>
m
o
u
s
e
−
>
e
l
e
p
h
a
n
t
elephant->tiger->cat->mouse->elephant
elephant−>tiger−>cat−>mouse−>elephant
每
种
动
物
棋
子
有
如
上
吃
的
关
系
每种动物棋子有如上吃的关系
每种动物棋子有如上吃的关系
给
两
种
动
物
,
问
前
者
是
否
赢
或
者
平
局
给两种动物,问前者是否赢或者平局
给两种动物,问前者是否赢或者平局
题解:
将
每
种
动
物
赋
上
一
个
数
0
−
3
,
然
后
二
维
数
组
建
一
个
图
将每种动物赋上一个数0-3,然后二维数组建一个图
将每种动物赋上一个数0−3,然后二维数组建一个图
如
果
能
赢
或
平
局
的
关
系
为
1
,
否
则
为
0
如果能赢或平局的关系为1,否则为0
如果能赢或平局的关系为1,否则为0
AC代码
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=5e5+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
map<string,int> m;
int g[4][4]={
1,1,1,0,
0,1,1,1,
1,0,1,1,
1,1,0,1
};
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
m["elephant"]=1,m["tiger"]=2,m["cat"]=3,m["mouse"]=4;
string s1,s2;
cin>>s1>>s2;
if(g[m[s1]-1][m[s2]-1])cout<<"tiangou yiwusuoyou"<<endl;
else cout<<"tiangou txdy"<<endl;
return 0;
}
B.组队
题意:
n
个
人
,
每
个
人
有
各
自
的
能
力
值
n个人,每个人有各自的能力值
n个人,每个人有各自的能力值
一
个
队
伍
中
能
力
值
的
极
差
不
能
超
过
k
一个队伍中能力值的极差不能超过k
一个队伍中能力值的极差不能超过k
问
最
多
可
以
多
少
个
人
一
起
组
队
问最多可以多少个人一起组队
问最多可以多少个人一起组队
题解:
先
从
小
到
大
排
序
,
枚
举
每
一
个
人
作
为
队
伍
最
小
的
先从小到大排序,枚举每一个人作为队伍最小的
先从小到大排序,枚举每一个人作为队伍最小的
通
过
使
用
u
p
p
e
r
_
b
o
u
n
d
找
出
大
于
k
−
a
i
的
第
一
个
位
置
通过使用upper\_bound找出大于k-a_i的第一个位置
通过使用upper_bound找出大于k−ai的第一个位置
位
置
减
一
到
枚
举
那
个
人
的
个
数
就
是
所
有
能
在
队
伍
里
的
人
位置减一到枚举那个人的个数就是所有能在队伍里的人
位置减一到枚举那个人的个数就是所有能在队伍里的人
AC代码
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=5e5+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
ll a[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int t;
cin>>t;
while(t--){
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+1+n);
int ans=0;
for(int i=1;i<=n;i++){
int p=upper_bound(a+1,a+1+n,k+a[i])-a-1;
ans=max(ans,p-i+1);
}
cout<<ans<<endl;
}
return 0;
}
J.建设道路
题意:
,
一
共
有
n
个
城
市
,
每
个
城
市
有
一
个
价
值
a
i
,一共有n个城市,每个城市有一个价值a_i
,一共有n个城市,每个城市有一个价值ai
现
在
需
要
再
每
两
两
城
市
之
间
建
一
条
路
现在需要再每两两城市之间建一条路
现在需要再每两两城市之间建一条路
这
条
路
的
花
费
为
(
a
i
−
a
j
)
2
这条路的花费为(a_i-a_j)^2
这条路的花费为(ai−aj)2
问
总
共
需
要
多
少
花
费
问总共需要多少花费
问总共需要多少花费
题解:
由
于
n
的
值
比
较
大
,
不
能
进
行
n
2
操
作
由于n的值比较大,不能进行n^2操作
由于n的值比较大,不能进行n2操作
将
公
式
展
开
,
a
i
2
−
2
∗
a
i
∗
a
j
+
a
j
2
将公式展开,a_i^2-2*a_i*a_j+a_j^2
将公式展开,ai2−2∗ai∗aj+aj2
由
于
对
每
个
城
市
来
说
,
都
要
和
另
外
n
−
1
个
城
市
建
路
由于对每个城市来说,都要和另外n-1个城市建路
由于对每个城市来说,都要和另外n−1个城市建路
所
以
每
个
城
市
都
要
先
加
上
一
个
(
n
−
1
)
∗
a
i
2
的
贡
献
所以每个城市都要先加上一个(n-1)*a_i^2的贡献
所以每个城市都要先加上一个(n−1)∗ai2的贡献
然
后
只
要
减
去
两
两
城
市
之
间
的
乘
积
的
二
倍
就
可
以
然后只要减去两两城市之间的乘积的二倍就可以
然后只要减去两两城市之间的乘积的二倍就可以
把
所
有
的
乘
积
放
到
一
块
,
其
实
就
是
每
个
城
市
的
价
值
乘
其
他
城
市
价
值
的
和
把所有的乘积放到一块,其实就是每个城市的价值乘其他城市价值的和
把所有的乘积放到一块,其实就是每个城市的价值乘其他城市价值的和
所
以
减
去
,
记
得
减
去
值
的
时
候
+
m
o
d
防
止
出
现
负
数
所以减去,记得减去值的时候+mod防止出现负数
所以减去,记得减去值的时候+mod防止出现负数
AC代码
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=1e9+7;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
ll a[maxn];
int main()
{
//ios::sync_with_stdio(false);
//cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n;
scanf("%d",&n);
ll sum=0;
for(int i=1;i<=n;i++)scanf("%lld",&a[i]),sum+=a[i]%mod;
ll ans=0;
for(int i=1;i<=n;i++){
sum=(sum-a[i]+mod)%mod;
ans=(ans+(n-1)*a[i]%mod*a[i]%mod)%mod;
ans=(ans-2*a[i]%mod*sum%mod+mod)%mod;
}
printf("%lld",ans);
return 0;
}
I.求和
题意:
存
在
一
棵
有
n
个
结
点
的
树
,
每
个
点
有
一
个
价
值
a
i
存在一棵有n个结点的树,每个点有一个价值a_i
存在一棵有n个结点的树,每个点有一个价值ai
现
在
需
要
进
行
两
种
操
作
(
共
m
次
)
现在需要进行两种操作(共m次)
现在需要进行两种操作(共m次)
1.
给
某
一
个
结
点
的
价
值
加
上
x
1.给某一个结点的价值加上x
1.给某一个结点的价值加上x
2.
查
询
一
个
结
点
和
他
子
树
的
全
部
价
值
2.查询一个结点和他子树的全部价值
2.查询一个结点和他子树的全部价值
题解:
现
在
需
要
进
行
不
断
更
新
和
查
询
现在需要进行不断更新和查询
现在需要进行不断更新和查询
所
以
第
一
个
想
到
的
就
是
线
段
树
或
者
树
状
数
组
所以第一个想到的就是线段树或者树状数组
所以第一个想到的就是线段树或者树状数组
但
是
我
们
没
办
法
维
护
每
个
结
点
的
子
树
但是我们没办法维护每个结点的子树
但是我们没办法维护每个结点的子树
就
想
到
了
用
d
f
s
序
,
给
某
个
结
点
重
新
定
义
就想到了用dfs序,给某个结点重新定义
就想到了用dfs序,给某个结点重新定义
并
用
l
i
和
r
i
之
间
的
数
维
护
的
自
己
到
所
有
子
节
点
并用l_i和r_i之间的数维护的自己到所有子节点
并用li和ri之间的数维护的自己到所有子节点
就
是
利
用
D
F
S
的
特
性
,
完
成
这
个
操
作
就是利用DFS的特性,完成这个操作
就是利用DFS的特性,完成这个操作
然
后
就
可
以
利
用
树
状
数
组
维
护
和
更
新
前
缀
和
然后就可以利用树状数组维护和更新前缀和
然后就可以利用树状数组维护和更新前缀和
然
后
查
询
的
点
只
要
找
到
这
个
点
i
的
l
i
到
r
i
的
区
间
大
小
就
可
以
了
然后查询的点只要找到这个点i的l_i到r_i的区间大小就可以了
然后查询的点只要找到这个点i的li到ri的区间大小就可以了
AC代码
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int l[maxn],r[maxn],cnt,a[maxn];
ll c[maxn];
//树状数组
int lowbit(int x)//返还x的最低位
{
return x&(-x);
}
ll query(int x)
{
ll s=0;
while(x>0)
{
s+=c[x];
x-=lowbit(x);
}
return s;
}
void add(int x,ll v)
{
while(x<maxn)
{
c[x]+=v;
x+=lowbit(x);
}
}
vector<int> g[maxn];
void dfs(int u,int fa){
l[u]=++cnt;
for(auto v:g[u]){
if(v==fa)continue;
dfs(v,u);
}
r[u]=cnt;
}
int main()
{
//ios::sync_with_stdio(false);
//cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
g[u].pb(v);
g[v].pb(u);
}
dfs(k,0);
for(int i=1;i<=n;i++)
add(l[i],a[i]);
while(m--){
int op;
scanf("%d",&op);
if(op==1){
int a,x;
scanf("%d%d",&a,&x);
add(l[a],x);
}
else{
int a;
scanf("%d",&a);
printf("%d\n",query(r[a])-query(l[a]-1));
}
}
return 0;
}
H.认认都是好朋友
题意:
你
有
1
e
9
个
手
下
你有1e9个手下
你有1e9个手下
你
收
到
了
m
张
纸
条
,
每
个
纸
条
上
有
a
,
b
,
c
三
个
数
你收到了m张纸条,每个纸条上有a,b,c三个数
你收到了m张纸条,每个纸条上有a,b,c三个数
如
果
c
=
1
表
示
你
的
手
下
a
和
b
是
朋
友
如果c=1表示你的手下a和b是朋友
如果c=1表示你的手下a和b是朋友
否
则
a
和
b
就
是
敌
人
否则a和b就是敌人
否则a和b就是敌人
(
朋
友
的
朋
友
也
是
朋
友
)
(朋友的朋友也是朋友)
(朋友的朋友也是朋友)
问
纸
条
是
否
会
产
生
矛
盾
的
地
方
(
两
个
人
是
朋
友
又
是
敌
人
)
问纸条是否会产生矛盾的地方(两个人是朋友又是敌人)
问纸条是否会产生矛盾的地方(两个人是朋友又是敌人)
题解:
最
后
的
提
示
很
明
显
,
这
道
题
是
并
查
集
最后的提示很明显,这道题是并查集
最后的提示很明显,这道题是并查集
但
是
这
道
题
明
确
说
了
,
你
有
1
e
9
个
手
下
但是这道题明确说了,你有1e9个手下
但是这道题明确说了,你有1e9个手下
所
以
说
明
你
的
a
和
b
非
常
大
,
肯
定
不
能
开
那
么
大
的
数
组
所以说明你的a和b非常大,肯定不能开那么大的数组
所以说明你的a和b非常大,肯定不能开那么大的数组
所
以
先
把
所
有
的
a
和
b
维
护
一
下
,
进
行
一
个
离
散
操
作
所以先把所有的a和b维护一下,进行一个离散操作
所以先把所有的a和b维护一下,进行一个离散操作
然
后
我
们
需
要
想
办
法
判
断
两
个
人
又
是
朋
友
又
是
敌
人
然后我们需要想办法判断两个人又是朋友又是敌人
然后我们需要想办法判断两个人又是朋友又是敌人
我
们
可
以
用
并
查
集
先
维
护
所
有
是
朋
友
的
人
我们可以用并查集先维护所有是朋友的人
我们可以用并查集先维护所有是朋友的人
然
后
再
找
所
有
是
敌
人
的
人
,
如
果
他
们
已
经
是
朋
友
了
,
说
明
出
现
矛
盾
然后再找所有是敌人的人,如果他们已经是朋友了,说明出现矛盾
然后再找所有是敌人的人,如果他们已经是朋友了,说明出现矛盾
AC代码
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=1e9+7;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=2e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
int a[maxn],b[maxn],c[maxn];
int d[maxn<<1],fa[maxn<<1];
int find(int x){
if(fa[x]==x)return x;
return fa[x]=find(fa[x]);
}
int main()
{
//ios::sync_with_stdio(false);
//cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int t;
t=read();
while(t--){
int n;
n=read();
for(int i=1;i<=n;i++){
a[i]=read(),b[i]=read(),c[i]=read();
d[2*i-1]=a[i],d[2*i]=b[i];
fa[2*i-1]=2*i-1,fa[2*i]=2*i;
}
sort(d+1,d+1+2*n);
int len=unique(d+1,d+1+2*n)-d-1;
bool f=0;
for(int i=1;i<=n;i++){
int x=lower_bound(d+1,d+1+len,a[i])-d;
int y=lower_bound(d+1,d+1+len,b[i])-d;
int p=find(x),q=find(y);
if(c[i])
fa[q]=p;
}
for(int i=1;i<=n;i++){
int x=lower_bound(d+1,d+1+len,a[i])-d;
int y=lower_bound(d+1,d+1+len,b[i])-d;
int p=find(x),q=find(y);
if(!c[i]&&p==q)f=1;
}
if(!f)printf("YES\n");
else printf("NO\n");
}
return 0;
}