A1 100pts
考试时暴力打表+发现三次函数于是暴力解方程。
更好的:
发现是在枚举子矩形并求面积,于是有:
\(\sum_{x}^n\sum_{y}^m x * y \times (n-x+1) * (m-y+1)\)
设\(f(x)=\sum_{x}^n x * (n-x+1)\)
\(=1*n + 2*(n-1) + 3*(n-2) + \cdots + (n-1)*2 + n*1\)
\(=\frac{(n+1)*n*n*3}{6} - (1*2+2*3+3*4+\cdot +(n-1)*n)\)
\(=\frac{(n+1)*n*n*3}{6} - \sum_{i} i*(i-1)\)
\(=\frac{(n+1)*n*n*3}{6} - \sum_{i} i^2-i\)
\(=\frac{(n+1)*n*n*3}{6} - \frac{n*(n+1)*(2*n+1)}{6} + \frac{n*(n+1)*3}{6}\)
\(=\frac{(n+1)*n*(3*n-(2*n+1)+3}{6}\)
\(=\frac{n*(n+1)*(n+2)}{6}\)
#include<bits/stdc++.h>
#define ll long long
#define R register ll
using namespace std;
namespace Luitaryi {
inline ll g() { R x=0,f=1;
register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
} const ll Inv2=500000004,Inv3=333333336,M=1000000007;
ll n,m;
inline void main() {
n=g(),m=g(); n%=M,m%=M;
printf("%lld\n",n*(n+1)%M*Inv2%M*(n+2)%M*Inv3%M*m%M*(m+1)%M*Inv2%M*(m+2)%M*Inv3%M);
}
} signed main() {Luitaryi::main(); return 0;}
A2 100pts
二分,枚举三个边界,二分第四个边界。
#include<bits/stdc++.h>
#define ll long long
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
} const int N=310;
int n,m,ans,q[N];
ll a[N][N];
inline void main() {
n=g(),m=g();
for(R i=1;i<=n;++i) for(R j=1;j<=m;++j) a[i][j]=g();
for(R i=1;i<=n;++i) for(R j=1;j<=m;++j) a[i][j]+=a[i][j-1];
for(R i=1;i<=n;++i) for(R j=1;j<=m;++j) a[i][j]+=a[i-1][j];
for(R i=1;i<=n;++i) for(R j=i;j<=n;++j) {
R t=0; register ll tmp;
for(R p=1;p<=m;++p) {
if(t) tmp=a[j][p-1]-a[j][q[t]-1]-a[i-1][p-1]+a[i-1][q[t]-1]; else tmp=-1;
if(tmp<0) q[++t]=p;
R l=1,r=t+1,md,pos; while(l<r) {
md=l+r>>1,pos=q[md];
if(a[j][p]-a[j][pos-1]-a[i-1][p]+a[i-1][pos-1]>0) r=md;
else l=md+1;
} if(l<t+1) { l=q[l];
ans=max(ans,(j-i+1)*(p-l+1));
}
}
} printf("%d\n",ans);
}
} signed main() {Luitaryi::main(); return 0;}
A3 20pts
OTZ ZBK && LQS
贪心:(真是应该多想想)
显然先排序,显然先魔法;
如何选择重 or 众:
若有一个血量为1或大于2个,众;
否则,重;
OTZ想不到想不到(其实当时想了想好像跟数量有关但是不会证QwQ)
#include<bits/stdc++.h>
#define ll long long
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
} const int N=100010;
int n,m,a[N];
inline void main() {
n=g(),m=g(); for(R i=1;i<=n;++i) a[i]=g();
sort(a+1,a+n+1); register ll ans=0,pos=1,add=0;
while(pos<=n) {
if(!m) {
for(R i=pos;i<=n;++i) ans+=(a[i]-add-1)*(n-i+1)+n-i;
break;
} if((a[pos]-add==1||n-pos+1>2)&&m) ++add,--m;
else if(m) a[pos]-=2,--m;
else --a[pos];
while(a[pos]<=add&&pos<=n) ++pos; ans+=n-pos+1;
} printf("%lld\n",ans);
}
} signed main() {Luitaryi::main(); return 0;}
B1
暴力匹配???惊了 \(n\leq 3000\)
开一个map建立单射,并开一个 \(bool vis[]\) 判种类(暂时没有反例)
#include<bits/stdc++.h>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
} const int N=2010;
unordered_map<int,int> mp; bool vis[N];
int n,m,c,a[N],b[N],ans[N],cnt,tot;
inline void main() {
n=g(),m=g(),c=g(); for(R i=1;i<=n;++i) a[i]=g();
for(R i=0;i<m;++i) b[i]=g(),tot+=(!vis[b[i]]),vis[b[i]]=true;
for(R i=1;i<=n-m+1;++i) {
memset(vis,0,sizeof vis),c=0;
for(R j=0;j<m;++j) {
c+=(!vis[a[i+j]]),vis[a[i+j]]=true;
if(mp.count(b[j])) {
if(mp[b[j]]==a[i+j]) continue;
else goto end;
} else mp[b[j]]=a[i+j];
} if(c>=tot) ans[++cnt]=i; end:mp.clear();
} printf("%d\n",cnt);
for(R i=1;i<=cnt;++i) printf("%d ",ans[i]);
}
} signed main() {Luitaryi::main(); return 0;}
B2
这个DP。。。想不到想不到ORZ
发现它既不能按位置直接DP,又不能按时间轴DP。
于是类似区间DP:\(f[l][r][0/1]\)表示 \([1,l]\) 与 \([r,n]\) 的案件已经处理完毕
这样就可以愉快的转移了。
#include<bits/stdc++.h>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
} const int N=1010,Inf=0x3f3f3f3f;
struct node { int d,t;
inline bool operator < (const node& that) const {return d<that.d;}
}a[N]; int n,H,B,f[N][N][2],ans=Inf;
inline void main() {
n=g(),H=g(),B=g(); for(R i=1;i<=n;++i) a[i].d=g(),a[i].t=g();
sort(a+1,a+n+1);
f[1][n][0]=max(a[1].t,a[1].d),
f[1][n][1]=max(a[n].d,a[n].t);
for(R len=n-2;~len;--len) for(R i=1;i+len<=n;++i) { R l=i,r=i+len;
f[l][r][0]=f[l][r][1]=Inf;
if(r<n)
f[l][r][1]=min(f[l][r][1],f[l][r+1][1]+a[r+1].d-a[r].d),
f[l][r][0]=min(f[l][r][0],f[l][r+1][1]+a[r+1].d-a[l].d);
if(l>1)
f[l][r][1]=min(f[l][r][1],f[l-1][r][0]+a[r].d-a[l-1].d),
f[l][r][0]=min(f[l][r][0],f[l-1][r][0]+a[l].d-a[l-1].d);
f[l][r][1]=max(f[l][r][1],a[r].t);
f[l][r][0]=max(f[l][r][0],a[l].t);
} for(R i=1;i<=n;++i)
ans=min(ans,min(f[i][i][0],f[i][i][1])+abs(a[i].d-B));
printf("%lld\n",ans);
}
} signed main() {Luitaryi::main(); return 0;}