因为第二天要去学校所以这一场没有打,,VP*n
A. Crossmarket
现有两人,其中一人要从左下角走到右上角,另一人要从左上角走到右下角,左下到右上的人每走一格会在当前格制作一个传送门,当某一人在一个有传送门的格子时,可以传送到另一个具有传送门的格子,每走一格需要一个单位的能量,问两人最少一共需要多少能量。
思路:可以制作传送门的人很显然只能一格一格走到终点,另一人尽可能传送最长的距离,计算一下即可。
AC Code:
#include <bits/stdc++.h>
typedef long long ll;
const int N=1e5+5;
int t,n,m;
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin>>t;
while(t--){
std::cin>>n>>m;
if(n==1&&m==1){
std::cout<<0<<'\n';
continue;
}
std::cout<<n+m-2+std::min(n,m)<<'\n';
}
return 0;
}
B. Beautiful Array
定义一个数组的beauty值为数组中每个数除以k向下取整的值之和,现在给出数组中元素个数,k的值,beauty值,所有元素之和,能否构造一个数组满足条件。
思路:我们可以尽量使构造方法简单。即beauty值集中在一个数。若是总和除以k小于b,那一定无法构造;若除以k大于b,我们可以让其中一个贡献beauty值的数为(b+1)*k-1,尽可能使用总和,其他的给每一个剩余位置赋值k-1(如果可以的话),若全部赋完值s还有剩余的数,那就不可能存在满足条件的数组。
AC Code:
#include <bits/stdc++.h>
typedef long long ll;
const int N=1e5+5;
int t;
ll n,k,b,s;
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin>>t;
while(t--){
std::cin>>n>>k>>b>>s;
if(s/k<b){
std::cout<<-1<<'\n';
continue;
}
std::vector<ll>ans(n+1,0);
if(s/k==b){
std::cout<<s;
for(int i=1;i<n;i++){
std::cout<<' '<<0;
}
std::cout<<'\n';
continue;
}
ans[1]=(b+1)*k-1;
s-=ans[1];
for(int i=2;i<=n;i++){
if(s>=k-1) ans[i]=k-1,s-=(k-1);
else if(s) ans[i]=s,s=0;
else if(s==0) ans[i]=0;
}
if(s){
std::cout<<-1<<'\n';
continue;
}
for(int i=1;i<=n;i++){
std::cout<<ans[i]<<" \n"[i==n];
}
}
return 0;
}
os:没开ll WA了一发
C. Monoblock
一个序列可以根据相邻数字是否相同分段,现给出一个数组,每次修改其中一个值,对于每次修改,输出其所有子串的分段数和。
思路:因为所有的修改都是基于原数组的,所以一开始计算原数组的值是必要的。可以采用双指针的方式从后向前计算以i为开头的子串的值。对于每次修改,讨论会对答案造成影响的情况,若第i个值与i-1个不同,但是修改完成为相同的,那相应的值会-1,然后找到包含这个数的区间作相应的修改,即(n-x+1)*(x-1),相反情况则是加上这个数。对于i个i+1的讨论同理。
AC Code:
#include <bits/stdc++.h>
typedef long long ll;
ll n,m;
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin>>n>>m;
std::vector<ll>a(n+2,0),f(n+2,0);
for(int i=1;i<=n;i++){
std::cin>>a[i];
}
ll sum=0;
for(int i=n;i>=1;i--){
int j=i;
while(j&&a[j-1]==a[i]) j--;
f[i]=f[i+1]+n-i+1;
sum+=f[i];
for(int k=i-1;k>=j;k--){
f[k]=f[k+1]+1,sum+=f[k];
}
i=j;
}
while(m--){
ll x,y;
std::cin>>x>>y;
if(a[x]==y){
std::cout<<sum<<'\n';
continue;
}
if(y==a[x-1]&&a[x]!=a[x-1]) sum-=(n-x+1)*(x-1);
if(y!=a[x-1]&&a[x]==a[x-1]) sum+=(n-x+1)*(x-1);
if(y==a[x+1]&&a[x]!=a[x+1]) sum-=(n-x)*x;
if(y!=a[x+1]&&a[x]==a[x+1]) sum+=(n-x)*x;
std::cout<<sum<<'\n';
a[x]=y;
}
return 0;
}
D. 2+ doors
给出q个关系,对于每个关系给出x,y,v三个值,表示a[x]|a[y]=v,构造一个字典序最小的数组,满足给出的条件。
思路:实质就是对于二进制下的v按照它的0或1分配给两个数0或1因为要字典序最小,所以尽可能多的赋0。对于v的位是0的情况,那一定是两数该位都是0,若是1的情况,则一定是一个0一个1,x和y靠前的那个赋0。但是最后会出现一些矛盾,即0和1的位置,那就按照前面的赋值来决定该位的情况。注意x==y时直接等于v。
AC Code:
#include <bits/stdc++.h>
#define int long long
const int N=2e5+5;
int n,m;
int ans[N];
struct node{
int x,v;
};
std::vector<node>vec[N];
signed main(){
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin>>n>>m;
for(int i=1;i<=m;i++){
int a,b,c;
std::cin>>a>>b>>c;
vec[a].push_back({b,c});
vec[b].push_back({a,c});
}
for(int i=1;i<=n;i++){
ans[i]=(1<<30)-1;
for(auto e:vec[i])
ans[i]&=e.v;
if(!vec[i].size()) ans[i]=0;
}
for(int i=1;i<=n;i++){
for(int j=0;j<30;j++){
if(ans[i]>>j&1){
bool flag=false;
for(auto e:vec[i])
if(!(ans[e.x]>>j&1)||e.x==i)
flag=true;
if(!flag) ans[i]-=(1<<j);
}
}
}
for(int i=1;i<=n;i++){
std::cout<<ans[i]<<' ';
}
std::cout<<'\n';
return 0;
}
感觉这场CD还好?虽然没做出来。。。