A题题意:给你一个按升序排好的序列,你需要交换ai和ai+m,问交换后这个序列最大权值算法是多少
样例这个图告诉我们交换后的权值变化是ai-m到ai-1这个区间加上ai*m,所以我们只要求出这个区间的值就行了,因为没有修改,所以我们只需要用前缀和即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read(){
ll s=0,f=1;char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;c=getchar();
if(c=='P')return 1;
else if(c=='H')return 0;
}
while(c>='0'&&c<='9'){
s=(s<<1)+(s<<3)+(c^48);c=getchar();
}
return f*s;
}
const int N=1555555;
ll n,m,k,a[N],s[N],sum,ans;
int main(){
int T=read();
while(T--){
n=read(),m=read();
sum=ans=0;
for(int i=1;i<=n;i++){
a[i]=read();
s[i]=s[i-1]+a[i];
sum+=a[i]*i;
}
for(int i=m;i<n;i++){
ans=max(ans,sum+s[i]-s[i-m]-a[i+1]*m);
}
printf("%lld\n",ans);
}
return 0;
}C题:题目要你求老师是否能在小Q到达办公室前够拦截小Q。
拦截方式有2种,在SK到达小Q之前拦下SK或者在小Q到达办公室之前拦下小Q。
因此我们只要比较SK到小Q的距离与老师到小Q的距离和SK到办公室的距离与SK到小Q的距离加上小Q到办公室的距离即可。
因为数据范围比较大,所以我们要用LCA来求距离。
找到他们的最近公共祖先,然后用他们两个的深度减去两个最近公共祖先的深度即为距离。
注意题目说的如果是同时到达办公室也是输出NO,还有组数据输出完后要清零,不然会影响下一组。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read(){
ll s=0,f=1;char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;c=getchar();
if(c=='P')return 1;
else if(c=='H')return 0;
}
while(c>='0'&&c<='9'){
s=(s<<1)+(s<<3)+(c^48);c=getchar();
}
return f*s;
}
const int N=1555555;
int n,m,k,deth[N],ans,f[N][22],l,r;
vector<int>q[N];
void dfs(int u,int fa,int deep){
f[u][0]=fa;
deth[u]=deep;
for(int i=1;(1<<i)<=deep;i++){
f[u][i]=f[f[u][i-1]][i-1];
}
for(int i=0;i<q[u].size();i++){
int t=q[u][i];if(t==fa)continue;
dfs(t,u,deep+1);
}
}
int lca(int x,int y){
if(deth[x]<deth[y])swap(x,y);
for(int i=20;i>=0;i--){
if(deth[x]-(1<<i)>=deth[y]){
x=f[x][i];
}
}
if(x==y)return x;
for(int i=20;i>=0;i--){
if(f[x][i]!=f[y][i]){
x=f[x][i],y=f[y][i];
}
}
return f[x][0];
}
int main(){
int T=read();
while(T--){
memset(q,0,sizeof(q));
memset(f,0,sizeof(f));
memset(deth,0,sizeof(deth));
n=read(),m=read();
for(int i=1;i<n;i++){
int x=read(),y=read();
q[x].push_back(y);
q[y].push_back(x);
}
dfs(1,1,0);
while(m--){
int x=read(),y=read(),z=read();
int k=lca(y,z),l=lca(x,z);
if(deth[x]-deth[l]-deth[l]<=deth[y]-deth[k]-deth[k]||deth[x]<deth[z]+deth[z]-deth[k]+deth[y]-deth[k]){
printf("YES\n");
}
else if(deth[x]+(deth[k]<<1)==(deth[z]<<1)+deth[y]){
if(lca(x,z)!=1){
printf("YES\n");
}
else{
printf("NO\n");
}
}
else{
printf("NO\n");
}
}
}
return 0;
}E题:题目说定义一个数字为幸运数字当且仅当它的所有数位都是4或者7。
只有2个数,很明显的2进制。我们提前打好表,把小于1000000000的数都记录下来,总共10位数大概有2^10-1种可能。
然后从1开是暴力枚举即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read(){
ll s=0,f=1;char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;c=getchar();
if(c=='P')return 1;
else if(c=='H')return 0;
}
while(c>='0'&&c<='9'){
s=(s<<1)+(s<<3)+(c^48);c=getchar();
}
return f*s;
}
const int N=1555555;
ll n,m,k,s[N],sum,ans,l,r;
vector<ll>a;
int main(){
for(int i=0;i<10;i++){
for(int j=0;j<(1<<(i+1));j++){
ll s=0;
for(int k=i;k>=0;k--){
s=(s<<1)+(s<<3)+(((1<<k)&j)?7:4);
}
a.push_back(s);
}
}
l=read(),r=read();
int i;
for(i=0;a[i]<=r;i++){
if(a[i]>=l){
ans+=a[i]*(a[i]-l+1);
l=a[i]+1;
}
}
if(l<=r){
ans+=a[i]*(r-l+1);
}
cout<<ans<<endl;
return 0;
}
京公网安备 11010502036488号