Codeforces Round #701 (Div. 2)
CF1485A
很不寻常的A题。
首先肯定有结论:第二个操作先做,再做第一个操作最优。
然后可以发现,操作次数不会超过一个很小的数。
所以可以枚举第二个操作的次数。然后计算即可。
这里取\(w=40\)
时间复杂度\(O(Tlog^2n)\)
code:
#include<cstdio>
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,m,k,x,y,z,t,ans,tot,now;
int main(){
register int i;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);ans=1e9;
for(i=0;i<=40;i++){
tot=i;
now=n;
if(!i&&m==1) continue;
while(now) now/=m+i,tot++;
ans=min(ans,tot);
}
printf("%d\n",ans);
}
}
CF1485B
因为只能有一个位置不同考虑枚举这个不同的位置。
显然这个不同的位置\(i\)的方案数是\(a_{i+1}-a_{i-1}-1\)。
然而要特别注意一下第一个和最后一个,第一个的下界是\(1\),最后一个上界是\(k\)。
然后前缀和一下即可。
code:
#include<cstdio>
using namespace std;
long long n,m,k,x,y,z,a[100039],q[100039];
int main(){
register int i;
scanf("%lld%lld%lld",&n,&m,&k);
for(i=1;i<=n;i++) scanf("%lld",&a[i]);
for(i=2;i<n;i++) q[i]=a[i+1]-a[i-1]-2,q[i]+=q[i-1];
for(i=1;i<=m;i++){
scanf("%lld%lld",&x,&y);
if(x==y) printf("%lld\n",k-1);
else{
printf("%lld\n",a[x+1]-2+q[y-1]-q[x]+k-a[y-1]-1);
}
}
}
CF1485C
设\(⌊\frac{a}{b}⌋=a \bmod b=k\)
然后发现\(a=k(b+1)\)
所以对于一个\(b\)的取值\(i\),这里的答案为\(⌊\frac{a}{i+1}⌋\)
然而因为余数不能大于除数。
所以这个答案要与\(i-1\)取\(\min\)
发现这部分单独处理的部分不会超过\(\sqrt n\),所以可以先求出上面一部分的答案,然后对于这一部分重新算。
上一部分套整除分块板子即可。
时间复杂度\(O(T\sqrt b)\)
code:
#include<cstdio>
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
long long n,m,k,x,y,z,T,ans,tot,pus;
inline long long h(long long x,long long m){
long long res=0,j;long long i,now;
for(i=1;i<=min(x+1,m);i=j+1){
j=m/(m/i);
res+=(j-i+1)*(m/i);now=m/i;
}res-=m;
if(i>x+1) res-=now*(i-x-2);
for(i=1;i*i<=m&&i<=x;i++){
res-=m/(i+1);
res+=i-1;
}
return res;
}
int main(){
// freopen("1.in","r",stdin);
register int i;
scanf("%d",&T);
while(T--){
scanf("%lld%lld",&x,&y);
printf("%lld\n",h(y,x));
}
CF1485D
可以发现\(a_{i,j}\)很小,所以从这里入手。
对于每个\(b_{i,j}\),我们使它为\(720720\),这是\(1\)到\(16\)所有数的最小公倍数。
但是这样没法完成相邻差为\(k^4\)的任务。
考虑将矩阵黑白染色,然后对于白块的\(b_{i,j}\)加上\(a_{i,j}^4\)即可。
code:
#include<cstdio>
using namespace std;
int n,m,k,x,y,z,a[539][539],b[530][539];
int main(){
register int i,j;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++){
for(j=1;j<=m;j++) scanf("%d",&a[i][j]);
}
for(i=1;i<=n;i++){
for(j=(i&1)+1;j<=m;j+=2) b[i][j]=a[i][j]*a[i][j]*a[i][j]*a[i][j];
}
for(i=1;i<=n;i++){
for(j=1;j<=m;j++) printf("%d ",b[i][j]+720720);printf("\n");
}
}
CF1485E
这种东西就可以逐层处理。
然后设\(dp_{i}\)表示红球在\(i\)点时的最大收益。
有两种转移渠道:由父节点直接转移,由非父节点下方到儿子且蓝球在当前节点之后交换得来。
父节点直接转移是\(O(1)\)的,但是非父节点转移是\(O(n)\)的。
考虑这个怎么处理。
首先套路离散\(a_i\)且拆掉绝对值,这样分类处理。
接着发现就可以开两颗线段树处理了。一棵线段树表示小于当前节点权值的转移,另一棵表示大于的。
这个树状数组似乎也可以。
时间复杂度\(O(nlogn)\),代码难度略大。
code:
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define CI const int &
#define ll long long
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int n,m,k,x,y,z,t,a[200039],d[200039],nows[200039],tots[200039],ys[200039],l,r,mid,now,minn,maxn;
ll ans,dp[200039];
struct yyy{int to,z;}tmp;
struct ljb{
int head,h[200039];yyy f[200039];
inline void add(int x,int y){f[++head]=(yyy){y,h[x]};h[x]=head;}
}s;
vector<int> g[200039];
struct tree{
ll sum[800039];
inline void clear(int x,int y,CI l=1,CI r=n,CI now=1){
if(x<=l&&r<=y){sum[now]=-1e18;return;}
int m=l+r>>1;
if(x<=m) clear(x,y,l,m,now<<1);
if(y>m) clear(x,y,m+1,r,now<<1|1);
}
inline ll find(int x,CI l=1,CI r=n,CI now=1){
if(l==r)return sum[now];
int m=l+r>>1;ll fs=-1e18;
if(x<=m) fs=find(x,l,m,now<<1);
else fs=find(x,m+1,r,now<<1|1);
return max(fs,sum[now]);
}
inline void get(int x,int y,ll z,CI l=1,CI r=n,CI now=1){
if(x<=l&&r<=y) {sum[now]=max(sum[now],z);return;}
int m=l+r>>1;
if(x<=m) get(x,y,z,l,m,now<<1);
if(y>m) get(x,y,z,m+1,r,now<<1|1);
}
}f1,f2;
inline void dfs(int x){
yyy tmp;
for(int cur=s.h[x];cur;cur=tmp.z){
tmp=s.f[cur];
d[tmp.to]=d[x]+1;dfs(tmp.to);
}
}
int main(){
freopen("1.in","r",stdin);
register int i,j;
scanf("%d",&t);memset(f1.sum,-0x3f,sizeof(f1.sum));memset(f2.sum,-0x3f,sizeof(f2.sum));
while(t--){
for(i=1;i<=n;i++) dp[i]=d[i]=s.h[i]=0,g[i].clear();s.head=0;ans=0;g[0].clear();
for(i=1;i<=4*n;i++) f1.sum[i]=f2.sum[i]=-1e18;
scanf("%d",&n);
for(i=2;i<=n;i++) scanf("%d",&x),s.add(x,i);
for(i=2;i<=n;i++) scanf("%d",&a[i]),nows[i-1]=a[i];
dfs(1);
for(i=1;i<=n;i++)g[d[i]].push_back(i);
sort(nows+1,nows+n);
for(i=1;i<n;i++) tots[i]=(i^1)?(tots[i-1]+(nows[i]!=nows[i-1])):1,ys[tots[i]]=nows[i];
for(i=2;i<=n;i++){
l=0;r=n-1;
while(l+1<r){
mid=l+r>>1;
if(nows[mid]<a[i]) l=mid;
else r=mid;
}
a[i]=tots[r];
}
for(i=1;;i++){
if(!g[i].size()) break;
for(j=0;j<g[i-1].size();j++){
now=g[i-1][j];yyy tmp;
for(int cur=s.h[now];cur;cur=tmp.z){
tmp=s.f[cur];
f1.get(1,a[tmp.to],dp[now]+ys[a[tmp.to]]);f2.get(a[tmp.to],n,dp[now]-ys[a[tmp.to]]);
}
}minn=1e9;maxn=-1e9;
for(j=0;j<g[i].size();j++) now=g[i][j],dp[now]=max(f1.find(a[now])-ys[a[now]],f2.find(a[now])+ys[a[now]]);
for(j=0;j<g[i].size();j++) now=g[i][j],minn=min(minn,ys[a[now]]),maxn=max(maxn,ys[a[now]]);
for(j=0;j<g[i-1].size();j++){
now=g[i-1][j];yyy tmp;
for(int cur=s.h[now];cur;cur=tmp.z){
tmp=s.f[cur];dp[tmp.to]=max(dp[tmp.to],dp[now]+max(maxn-ys[a[tmp.to]],ys[a[tmp.to]]-minn));
}
}
for(j=0;j<g[i-1].size();j++){
now=g[i-1][j];yyy tmp;
for(int cur=s.h[now];cur;cur=tmp.z){
tmp=s.f[cur];
f1.clear(1,a[tmp.to]);f2.clear(a[tmp.to],n);
}
}
}
for(i=1;i<=n;i++) ans=max(ans,dp[i]);
printf("%lld\n",ans);
}
}
CF1485F
咕咕咕