难度排序越来越阴间了。
圣诞老人有一个 Bat
和一双 Glove
,他会选一个价格高的送给你。给定两者的价格(保证不同),输出他会送你 Bat
还是 Glove
。
直接输出即可。
#include
using namespace std;
#define int long long
#define max(a,b) (a>b?a:b)
int a,b;
signed main(){
cin>>a>>b;
if(a>b) cout<<"Bat"<<endl;
else cout<<"Glove"<<endl;
return 0;
}
小F要摆放圣诞树。他先在 A A A 点摆一棵树。随后从 A A A 点开始,向左每隔 k k k 个单位长度摆一棵树,向右每隔 k k k 个单位长度摆一棵树。他想问你, l l l 和 r r r 之间一共有几棵圣诞(包含 l , r l,r l,r)。
A A A 在 l , r l,r l,r 中间则查询 l , A l,A l,A 之间有多少棵,加上 A , r A,r A,r 之间有多少棵,再减一即可。
A A A 在 l l l 左边则查询 A , r A,r A,r 之间有多少棵,减去 A , l − 1 A,l-1 A,l−1 之间的棵数。
A A A 在 r r r 右边则查询 l , A l,A l,A 之间有多少棵,减去 r + 1 , A r+1,A r+1,A 之间的棵树。
注意到我们这样定义的话,查询的一个端点一定是 A A A,那么就很好计算了。
#include
using namespace std;
#define int long long
#define max(a,b) (a>b?a:b)
int A,k,l,r,ans=0;
int getans(int L,int to){
return (to-L)/k+1;
}
signed main(){
cin>>A>>k>>l>>r;
if(l<=A&&A<=r) ans=getans(l,A)+getans(A,r)-1;
else if(A<l) ans=getans(A,r)-getans(A,l-1);
else ans=getans(l,A)-getans(r+1,A);
cout<<ans<<endl;
return 0;
}
有 n n n 双袜子,编号为 1 , 2 , ⋯ , n 1,2,\cdots,n 1,2,⋯,n。现在丢失了 k k k 只袜子,分别为 a 1 , a 2 , ⋯ , a k a_1,a_2,\cdots,a_k a1,a2,⋯,ak。 a a a 中的数两两不同。你要将剩余的袜子匹配成双(有可能最终余下一只),若将编号为 i , j i,j i,j 的袜子匹配会获得 max ( i , j ) − min ( i , j ) \max(i,j)-\min(i,j) max(i,j)−min(i,j) 的不满意值。求不满意值最小为多少。
不妨将袜子的编号抽象到数轴上,那么 i , j i,j i,j 袜子的不满意度就成了它们之间的距离。为什么要这么干呢?因为这样我们发现,对于 i , j i,j i,j 余下一只袜子, x x x 余下两只袜子时,若 i < x < j i < x < j i<x<j,那么无论怎么匹配不满意值都是一样的。
所以不妨将自身成双的袜子匹配掉,再匹配单只袜子,即匹配 a 1 , a 2 , ⋯ , a k a_1,a_2,\cdots,a_k a1,a2,⋯,ak。 k k k 为偶数时显然相邻两个匹配最优。 k k k 为奇数时枚举扔掉哪个袜子,剩余的两两匹配。可以通过一个前缀和加后缀和维护扔掉袜子后匹配的不满意值(注意到给定的 a a a 数组是有序的)。
#include
using namespace std;
#define int long long
#define max(a,b) (a>b?a:b)
int n,k,a[200010],num1[200010],num2[200010],ans=0;
signed main(){
cin>>n>>k;
for(int i=1;i<=k;i++) cin>>a[i];
for(int i=2;i<=k;i+=2) num1[i]=num1[i-2]+a[i]-a[i-1];
for(int i=k-1;i>=2;i-=2) num2[i]=num2[i+2]+a[i+1]-a[i];
if(k%2==0) cout<<num1[k]<<endl;
else{
ans=0x3f3f3f3f3f3f3f3f;
for(int i=1;i<=k;i++){
if(i%2==1) ans=min(ans,num1[i-1]+num2[i+1]);
else ans=min(ans,num1[i-2]+num2[i+2]+a[i+1]-a[i-1]);
}
cout<<ans<<endl;
}
return 0;
}
有 n n n 个雪橇,拉动第 i i i 个雪橇需要 a i a_i ai 头麋鹿。一头麋鹿只能拉一个雪橇。有 q q q 次询问,每次询问有 x x x 头麋鹿的情况下,最多能拉动多少雪橇。
裸的贪心。显然我们想选择 a i a_i ai 小的雪橇先拉。所以将 a a a 先排个序,然后做一个前缀和,对于每次询问,二分查找最多能拉的雪橇数即可。
#include
using namespace std;
#define int long long
#define max(a,b) (a>b?a:b)
int n,q,a[200010],num[200010];
signed main(){
cin>>n>>q;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
for(int i=1;i<=n;i++) num[i]=num[i-1]+a[i];
while(q--){
int x;
cin>>x;
cout<<upper_bound(num+1,num+n+1,x)-num-1<<endl;
}
return 0;
}
给定一个 n n n 行 m m m 列的矩阵,每个格子为 #
或 .
。定义这个矩阵的美丽值为 #
连通块的个数。#
连通块是指从这个 #
出发,往上下左右走能走到的最大的全部为 #
的区域。现在随机将一个 .
变成 #
,求期望美丽值。
考虑染色。对每个 #
连通块进行染色(打上序号),然后遍历所有的 .
。如果这个 .
上下为 #
且序号不同,说明将这个 .
变成 #
后美丽值会少 1 1 1。左右、左上、左下、右上、右下情况类似,也就是说判断将其变成 #
后会把原来多少个不相连的 #
连通块相连。
#include
using namespace std;
#define int long long
#define max(a,b) (a>b?a:b)
int n,m,vis[1010][1010],col[1010][1010],cnt=0,sum=0,ans=0,mod=998244353;
string s[1010];
int KSM(int a,int b){
int ans=1;
while(b){
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
void dfs(int x,int y,int C){
//染色
if(x<=0||y<=0||x>n||y>m) return;
if(vis[x][y]||s[x][y]=='.') return;
col[x][y]=C;
vis[x][y]=1;
dfs(x+1,y,C);
dfs(x,y+1,C);
dfs(x-1,y,C);
dfs(x,y-1,C);
}
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>s[i],s[i]=" "+s[i];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++) if(!vis[i][j]&&s[i][j]=='#') dfs(i,j,++cnt);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(s[i][j]=='.'){
set<int> s;
if(vis[i-1][j]) s.insert(col[i-1][j]);
if(vis[i+1][j]) s.insert(col[i+1][j]);
if(vis[i][j+1]) s.insert(col[i][j+1]);
if(vis[i][j-1]) s.insert(col[i][j-1]);
//查找能够把多少个原本不相连的连通块连起来
sum=(sum+cnt+1-s.size())%mod;
ans++;
}
}
}
cout<<(sum*KSM(ans,mod-2)%mod)<<endl;
return 0;
}
圣诞老人的家在 ( S x , S y ) (S_x,S_y) (Sx,Sy)。他要给 n n n 个编号为 1 , 2 , ⋯ , n 1,2,\cdots,n 1,2,⋯,n 小朋友各送一个礼物,编号为 i i i 的小朋友在 ( x i , y i ) (x_i,y_i) (xi,yi)。圣诞老人的礼物袋最多只能装 k k k 个礼物,他可以选择在任何时刻回家将礼物袋中的礼物补满。他必须按小朋友的编号送礼物。求他给所有小朋友送完礼物并回家的路程最小值。
考虑动态规划。 d p i , j dp_{i,j} dpi,j 表示当前到第 i i i 个小朋友,手中还剩 j j j 个礼物时的最短路程。显然有一个 n 2 n^2 n2 的做法,即 d p i , j = d p i − 1 , j + 1 + D i s ( i , i − 1 ) dp_{i,j}=dp_{i-1,j+1}+Dis(i,i-1) dpi,j=dpi−1,j+1+Dis(i,i−1)。其中 D i s ( i , j ) Dis(i,j) Dis(i,j) 表示从编号为 i i i 的小朋友处走到编号为 j j j 的小朋友处的距离。要注意 d p i , k dp_{i,k} dpi,k 的转移, d p i , k dp_{i,k} dpi,k 应该是从 d p i − 1 , j dp_{i-1,j} dpi−1,j 中选一个最小的,加上 D i s ( i − 1 , 0 ) + D i s ( 0 , i ) Dis(i-1,0)+Dis(0,i) Dis(i−1,0)+Dis(0,i)。假设圣诞老人的家编号为 0 0 0。
考虑优化。发现有一堆东西是一样的,可以选择线段树优化。即,更新 d p i , j dp_{i,j} dpi,j 相当于区间加,更新 d p i , k dp_{i,k} dpi,k 相当于区间查询最小值。
#include
using namespace std;
#define int long long
#define max(a,b) (a>b?a:b)
int n,k,x[200010],y[200010];
double Dis(int a,int b){
return sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]));
}
struct node{
double sum,lz;
int l,r;
}t[400010<<2];
void Build(int rt,int l,int r){
t[rt]={0,0,l,r};
if(l==r) return;
int mid=(l+r)>>1;
Build(rt<<1,l,mid);
Build(rt<<1|1,mid+1,r);
t[rt].sum=min(t[rt<<1].sum,t[rt<<1|1].sum);
}
void Pushdown(int rt){
int l=rt<<1,r=rt<<1|1;
double ad=t[rt].lz;
t[l].sum+=ad,t[l].lz+=ad;
t[r].sum+=ad,t[r].lz+=ad;
t[rt].lz=0;
}
void Update(int rt,int l,int r,double ad){
if(t[rt].r<l||r<t[rt].l) return;
if(l<=t[rt].l&&t[rt].r<=r){
t[rt].lz+=ad;
t[rt].sum+=ad;
return;
}
Pushdown(rt);
Update(rt<<1,l,r,ad);
Update(rt<<1|1,l,r,ad);
t[rt].sum=min(t[rt<<1].sum,t[rt<<1|1].sum);
}
double Query(int rt,int l,int r){
if(t[rt].r<l||r<t[rt].l) return 1000000000000000000;
if(l<=t[rt].l&&t[rt].r<=r) return t[rt].sum;
Pushdown(rt);
return min(Query(rt<<1,l,r),Query(rt<<1|1,l,r));
}
signed main(){
cin>>n>>k;
cin>>x[0]>>y[0];
//圣诞老人的家
for(int i=1;i<=n;i++) cin>>x[i]>>y[i];
Build(1,1,400005);
for(int i=1;i<=n;i++){
double Min=Query(1,i,i+k-1),Add=0;
//从前面找最小的
if(i!=1) Add=Dis(0,i-1);
Update(1,i+k,i+k,Min+Add+Dis(0,i));
//更新 k
Update(1,i+1,i+k-1,Dis(i-1,i));
//更新 1~k-1
//实际上整体完成了一次平移
}
printf("%.15lf\n",Query(1,n+1,n+k)+Dis(n,0));
return 0;
}