9.14题解
T1
对于这个数据范围,我们发现我们不断的乘$b$,什么都不加,$b$是最小的2,$T$是最小的1,最多也就乘大概60次就足够了,也就是说我们完全可以枚举乘过几个$b$,既然我们确定了需要乘几个$b$,那加$a$也就可以确定了,我们可以得到$m{\times}a=T-S{\times}b^x$,我们就可以得到m的值,而关键就是求出$b$进制下的m,这样的话我们就可以直接统计加了几次$a$了,显然是个进制转化,照着二进制乱搞就可以了
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #define maxx 1001000 5 #define ll long long 6 #define inf 2000000000000000000 7 using namespace std; 8 ll S,T,a,b,base=1,m,ans=inf; 9 ll ksm(ll a,int b) 10 { 11 ll ans=1; 12 while(b) 13 { 14 if(b&1) ans*=a; 15 b=b>>1; a*=a; 16 } 17 return ans; 18 } 19 int main() 20 { 21 scanf("%lld%lld%lld%lld",&S,&T,&a,&b); 22 for(int i=0;i<=64;++i) 23 { 24 if(base>T/S) break; 25 ll cha=T-S*base; 26 if(cha%a==0) m=cha/a; 27 else {base*=b; continue;} 28 ll sum=i; 29 for(int j=i;j>=0;--j) 30 { 31 ll mi=ksm(b,j); 32 sum+=m/mi; m%=mi; 33 } 34 base*=b; ans=min(ans,sum); 35 } 36 printf("%lld\n",ans); 37 return 0; 38 }
T2
不知道为什么我像失忆了一般,我明明记得我打完了这道题,然而我残存的代码告诉我,我刚开始码他。。。。咕了
T3
他们发现了费用随特殊加热器的使用次数呈单谷函数,我们就可以愉快的开启三分的旅程,怎么$check$呢?考虑贪心,由于我们每次用普通加热器都会覆盖一段区间,所以用树状数组进行差分,首先预处理出来我如果在当前这个点使用普通加热器,最多能覆盖到哪一个点,$check$的时候从第一个点开始,如果还没有达到希望的能量,就使用加热器使他达到,顺带使可以和他一起使用加热器的点需要的能量值变少即可
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<bits/stdc++.h> 6 #define maxn 100100 7 #define int long long 8 using namespace std; 9 struct node{ 10 int l,r; 11 }a[maxn]; 12 int n,m,t,co_ba,maxx,l=0,r,head=1,minn=0x7fffffffffffffff; 13 int p[maxn],flag[maxn],c[maxn],to[maxn],sf[maxn]; 14 bool cmp(const node &a,const node &b) 15 { 16 return a.l<b.l; 17 } 18 int lowbit(int x) 19 { 20 return x&(-x); 21 } 22 void add(int pos,int w) 23 { 24 for(;pos<=n;pos+=lowbit(pos)) c[pos]+=w; 25 } 26 int query(int pos) 27 { 28 int ans=0; 29 for(;pos>0;pos-=lowbit(pos)) ans+=c[pos]; 30 return ans; 31 } 32 int check(int x) 33 { 34 memset(c,0,sizeof(c)); 35 int sum=x*t; 36 for(int i=1;i<=n;++i) sf[i]=max(1ll*0,p[i]-x); 37 for(int i=1;i<=n;++i) add(i,sf[i]-sf[i-1]); 38 for(int i=1;i<=n;++i) 39 { 40 int ww=query(i); 41 if(ww<=0) continue; 42 sum+=ww; add(i,-ww); add(to[i]+1,ww); 43 } 44 return sum; 45 } 46 signed main() 47 { 48 scanf("%lld%lld%lld",&n,&m,&t); 49 for(int i=1;i<=n;++i) scanf("%lld",&p[i]); 50 for(int i=1;i<=m;++i) 51 { 52 scanf("%lld%lld",&a[i].l,&a[i].r); 53 for(int j=a[i].l;j<=a[i].r;++j) flag[j]=1; 54 } 55 sort(a+1,a+m+1,cmp); 56 for(int i=1;i<=n;++i) 57 if(!flag[i]) maxx=max(maxx,p[i]); 58 for(int i=1;i<=n;++i) {p[i]=max(1ll*0,p[i]-maxx); r=max(r,p[i]);} 59 co_ba=t*maxx; maxx=0; 60 for(int i=1;i<=n;++i) 61 { 62 while(a[head].l<=i&&head<=m) {maxx=max(maxx,a[head].r); head++;} 63 to[i]=maxx; 64 } 65 while(l+1<r) 66 { 67 int mid=(l+r)>>1; 68 int cost1=check(mid-1),cost2=check(mid); 69 minn=min(minn,cost1); minn=min(minn,cost2); 70 if(cost1>=cost2) l=mid; 71 else r=mid; 72 } 73 co_ba+=minn; printf("%lld\n",co_ba); 74 return 0; 75 }
T4
说一下思路过程吧,一开始打了个暴力,枚举连接的两个端点直接求花费,然后只有30分,后来打了个小表发现一个端点确定之后另一个端点可以三分,就有了$T60$的好成绩,然后我就突然发现两个端点似乎可以三分套三分,但是由于中间平的地方太多,单谷不严格,所以三分本来就是死的,三分套三分就死透了,然后我惊讶的得知这道题数据水到随机化可$A$,然后我就$A$了。。。。。
1 #include<iostream> 2 #include<cstdio> 3 #define maxn 100010 4 using namespace std; 5 struct node{ 6 int l,r; 7 }q[maxn]; 8 int n,m,head,tail,ans=0x7fffffff; 9 int check() 10 { 11 int maxx=0; 12 for(int i=1;i<=m;++i) 13 { 14 int len=q[i].r-q[i].l; 15 if(head>q[i].l&&tail<q[i].r) len=min(len,head-q[i].l+q[i].r-tail); 16 else if(head<=q[i].l&&tail>=q[i].r) len=min(q[i].r-q[i].l,q[i].l-head+tail-q[i].r); 17 else if(head>q[i].l&&tail>=q[i].r) len=min(q[i].r-q[i].l,head-q[i].l+tail-q[i].r); 18 else if(head<=q[i].l&&tail<q[i].r) len=min(q[i].r-q[i].l,q[i].l-head+q[i].r-tail); 19 maxx=max(maxx,len); 20 if(maxx>=ans) return maxx; 21 } 22 return maxx; 23 } 24 int main() 25 { 26 scanf("%d%d",&n,&m); 27 for(int i=1;i<=m;++i) scanf("%d%d",&q[i].l,&q[i].r); 28 if(m==1) {printf("0\n"); return 0;} 29 for(int i=1;i<=n;++i) 30 { 31 int l=i+2,r=n; 32 while(l+1<r) 33 { 34 int mid=(l+r)>>1; 35 head=i; tail=mid-1; 36 int cost1=check(); 37 head=i; tail=mid; 38 int cost2=check(); 39 ans=min(ans,cost1); ans=min(ans,cost2); 40 if(cost1>=cost2) l=mid; 41 else r=mid; 42 } 43 } 44 printf("%d\n",ans); 45 return 0; 46 }