(D1T1)铺地毯((OK))
(D1T2)选择客栈((OK))
(D2T1)计算系数((OK))
(D2T3)观光公交((OK))
(Mayan)游戏先咕一下.
(D1T1)就直接倒序判断该点是否被地毯覆盖即可.
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=10005;
struct dt{int x1,y1,x2,y2;}a[N];
int main(){
int n=read();
for(int i=1;i<=n;++i){
a[i].x1=read();a[i].y1=read();
a[i].x2=a[i].x1+read();a[i].y2=a[i].y1+read();
}
int x=read(),y=read();
for(int i=n;i>=1;--i){
if(x>=a[i].x1&&x<=a[i].x2&&y>=a[i].y1&&y<=a[i].y2){
printf("%d
",i);return 0;
}
}
puts("-1");
return 0;
}
(D1T2)做过好多次了,最简单的是预处理前缀和,然后就可以(O(nk))计算了.还有一种更优秀的做法可以达到(O(n)),一边扫描一边维护那个前缀和,每次的(i)计算以该点为右端点的贡献即可.
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=2e5+5;
int col[N],val[N],sum[51];
int main(){
int n=read(),k=read(),p=read();
for(int i=1;i<=n;++i)col[i]=read(),val[i]=read();
int ans=0,last=0;
for(int i=1;i<=n;++i){
if(val[i]<=p){
for(int j=last+1;j<i;++j)++sum[col[j]];
last=i;ans+=sum[col[i]];++sum[col[i]];
}
else ans+=sum[col[i]];
}
printf("%d
",ans);
return 0;
}
(D1T3)咕咕咕.
(D2T1)额,如果没有(a,b)就是多项式,那么系数就是组合数,然后现在有(a,b),其实就是乘上(a^n,b^m)即可.组合数可以递推也可以直接处理好阶乘及其逆元之后(O(1))计算.
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int mod=10007;
int f[1005][1005];
inline ll ksm(int a,int b){
ll cnt=1;
while(b){
if(b&1)cnt=(1ll*cnt*a)%mod;
a=(1ll*a*a)%mod;
b>>=1;
}
return cnt;
}
int main(){
int a=read(),b=read(),k=read(),n=read(),m=read();
for(int i=0;i<=k;++i){
f[i][0]=1;
for(int j=1;j<=i;++j)f[i][j]=(f[i-1][j]+f[i-1][j-1])%mod;
}
printf("%lld
",1ll*f[k][k-n]*ksm(a,n)%mod*ksm(b,m)%mod);
return 0;
}
(D2T2)刚开始一看到这题:显然三分啊,因为(abs(S-T))是一个关于(W)的开口向上的二次函数,然后专门去速成了一波三分,结果只有(95)分,不想管了.放个代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline ll read(){
ll x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=2e5+5;
int n,m;ll S,sum1[N],sum2[N];
int w[N],v[N],l[N],r[N];
vector<int>g[N];
inline ll calc(int W){
ll ans=0;
for(int i=1;i<=n;++i){
sum1[i]=sum1[i-1];sum2[i]=sum2[i-1];
if(w[i]>=W){
++sum1[i];sum2[i]+=v[i];
}
for(int j=0;j<(int)g[i].size();++j){
int l=g[i][j],r=i;
ans+=1ll*(sum1[r]-sum1[l-1])*(sum2[r]-sum2[l-1]);
}
}
return abs(S-ans);
}
int main(){
n=read();m=read();S=read();
for(int i=1;i<=n;++i)w[i]=read(),v[i]=read();
for(int i=1;i<=m;++i)l[i]=read(),r[i]=read(),g[r[i]].push_back(l[i]);
int l=0,r=1e6,mid1,mid2;
while(l<r){
mid1=(l+r)>>1;
mid2=(mid1+r)>>1;
ll f1=calc(mid1),f2=calc(mid2);
if(f1>f2)l=mid1;
if(f1<f2)r=mid2;
if(f1==f2){
if(mid1==mid2){
printf("%lld
",f1);
return 0;
}
r=mid2;
}
}
return 0;
}
然后因为(S)是个定值,所以我们先不要考虑,那么(T)是一个关于(W)的单增函数,就可以二分答案了.
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline ll read(){
ll x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=2e5+5;
int n,m;ll S,sum1[N],sum2[N];
int w[N],v[N],l[N],r[N];
vector<int>g[N];
inline ll calc(int W){
ll ans=0;
for(int i=1;i<=n;++i){
sum1[i]=sum1[i-1];sum2[i]=sum2[i-1];
if(w[i]>=W){
++sum1[i];sum2[i]+=v[i];
}
for(int j=0;j<(int)g[i].size();++j){
int l=g[i][j],r=i;
ans+=1ll*(sum1[r]-sum1[l-1])*(sum2[r]-sum2[l-1]);
}
}
return ans;
}
int main(){
n=read();m=read();S=read();
for(int i=1;i<=n;++i)w[i]=read(),v[i]=read();
for(int i=1;i<=m;++i)l[i]=read(),r[i]=read(),g[r[i]].push_back(l[i]);
int l=0,r=1e6,mid;ll ans;
while(l<=r){
mid=(l+r)>>1;
ll T=calc(mid);
if(T<=S){
r=mid-1;
if(ans>S-T)ans=S-T;
}
else{
l=mid+1;
if(ans>T-S)ans=T-S;
}
}
printf("%lld
",ans);
return 0;
}
(D2T3)这道题好像从去年开始就一直被安利,然后一直不会做,当然现在还是不会自己做...
预处理出不使用加速器的情况下,公交车到达每个车站的时间(arrive[i]).
然后考虑用一次加速器之后能影响到多少车站的乘客?假设当前在车站(i)到车站(i+1)之间使用一次加速器,然后(i)~(j)这些车站的(arrive)都可以减(1),其中(j)满足(arrive[j-1]>late[j-1],arrive[j]<=late[j]).这个可以(O(n))找到.
然后这样操作(k)次即可.时间复杂度就是(O(nk)).
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=1005;
const int M=10005;
int d[N],off[N],late[N],arrive[N];
struct ck{int tim,st,ed;}a[M];
int main(){
int n=read(),m=read(),k=read();
for(int i=1;i<n;++i)d[i]=read();
for(int i=1;i<=m;++i){
a[i].tim=read();a[i].st=read();a[i].ed=read();
late[a[i].st]=max(late[a[i].st],a[i].tim);++off[a[i].ed];
}
for(int i=2;i<=n;++i)arrive[i]=max(arrive[i-1],late[i-1])+d[i-1];
while(k--){
int max_val=0,pos=0;
for(int i=1;i<n;++i){
if(!d[i])continue;//距离不能减到0
int max_cnt=0,j=i+1;
for(;j<=n;++j){
max_cnt+=off[j];
if(arrive[j]<=late[j])break;
}
if(max_cnt>max_val){
max_val=max_cnt;
pos=i;
}
i=j-1;//没有这一句虽然能过本题,但是时间复杂度理论上达到了kn^2,只能说NOIP数据水
}
--d[pos];
for(int j=pos+1;j<=n;++j){
--arrive[j];
if(arrive[j]<late[j])break;
}
}
int ans=0;
for(int i=1;i<=m;++i)ans+=arrive[a[i].ed]-a[i].tim;
printf("%d
",ans);
return 0;
}