打地鼠
它竟然是道蓝题首先对于检验某种规格的锤子是否可行,一定是要从左上角开始消除,证明很简单,不再赘述。当然暴力枚举长宽的效率是很低的,让我们加 yi 点点小优化。
- 对于一种规格,若它的面积不能被总数整除,肯定不行。
- 其实上面那个优化已经够了,但优化永无止境,若有一个大面积可行,那么小面积肯定不优。
- 若你精(xian)益(de)求(dan)精(teng),在检验时,还可以差分优化。
#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void read(T &x){
T ch=getchar(),xx=1;x=0;
while(!isdigit(ch)) xx=ch=='-'?-1:xx,ch=getchar();
while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
x*=xx;
}
template<typename T>inline void prt(T x){
if(x>9) prt(x/10);
putchar(x%10|48);
}
#define N 110
int f[N][N],a[N][N];
int n,m,ans,s,sum;
int get(int x,int y){
memcpy(a,f,sizeof a);
int ret=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j){
if(a[i][j]==0) continue;
else if(a[i][j]>0 && i+x-1<=n && j+y-1<=m){
int z=a[i][j];ret+=z;
for(int k=i;k<=i+x-1;++k)
a[k][j]-=z,a[k][j+y]+=z;//差分
} else return INT_MAX;
}
return ret;
}
int main(){
read(n),read(m);
for(int i=1;i<=n;++i)
for(int j=1,x,y=0;j<=m;++j)
read(x),f[i][j]=x-y,y=x,sum+=x;//差分
ans=get(1,1);s=1;
for(int i=n;i>=1;--i){
if(sum%i) continue;//剪枝 1
for(int j=m;j>=1;--j){
if(i*j<s) break;//剪枝 2
if(sum%(i*j)) continue;//剪枝 1
int t=get(i,j);
if(t!=INT_MAX){
ans=min(t,ans);
s=i*j;//剪枝 2
break;
}
}
}
prt(ans);
}
消防
很好的一道理解树的直径的题。
首先让我们思考一个问题,路径该在哪? 答案是一定在直径上。
证明:
假设路径不完全在直径上,那离路径最远的点一定是直径的两个端点之一(为什么?因为它是直径,最远的点不在直径上还能在哪?),又因为是直径,那总能找到一个点比直径近,我们又想尽量使最大值变小,那为什么不让路径在直径上,让这个点作为答案呢?
证毕。
那既然路径在直径上,那答案就出来了。
设
k
k
k 是直径上的点,
D
k
D_k
Dk 是
k
k
k 不经过直径能到达最远的点,
S
k
S_k
Sk 表示直径上点的集合,
q
,
p
q,p
q,p 为选的路径的端点,
1
1
1 和
t
t
t 为直径的两个端点。答案即是
max
(
max
i
≤
k
<
j
{
D
k
}
,
d
i
s
t
(
1
,
q
)
,
d
i
s
t
(
p
,
t
)
)
\max(\max_{i\leq k<j}\{D_k\},dist(1,q),dist(p,t))
max(i≤k<jmax{Dk},dist(1,q),dist(p,t))由于直径的最长性,上式可以变为
max
(
max
k
∈
S
k
{
D
k
}
,
d
i
s
t
(
1
,
q
)
,
d
i
s
t
(
p
,
t
)
)
\max(\max_{k\in S_k}\{D_k\},dist(1,q),dist(p,t))
max(k∈Skmax{Dk},dist(1,q),dist(p,t))可见
D
k
D_k
Dk 是一个定值,不随
q
,
p
q,p
q,p 变化。而对于
q
,
p
q,p
q,p 的枚举,由于范围限定,对于
q
q
q 而言,
p
p
p 是单调变化的。即最后
O
(
n
)
O(n)
O(n) 扫描一遍就行了。
#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void read(T &x){
T ch=getchar(),xx=1;x=0;
while(!isdigit(ch)) xx=ch=='-'?-1:xx,ch=getchar();
while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
x*=xx;
}
template<typename T>inline void prt(T x){
if(x>9) prt(x/10);
putchar(x%10|48);
}
#define N 500010
int head[N],to[N<<1],nxt[N<<1],len[N<<1],cnt;
int fa[N],f[N],d[N],a[N];
int n,s,m,temp,ans=0x7f7f7f7f;
bool v[N];
void add(int x,int y,int z) {
to[++cnt]=y,len[cnt]=z,nxt[cnt]=head[x],head[x]=cnt;
}
void dfs(int x){
for(int i=head[x];i;i=nxt[i]){
int y=to[i],z=len[i];
if(y==fa[x]) continue;
fa[y]=x;
d[y]=d[x]+z;
dfs(y);
}
}
void pre(){
dfs(1);
int x=1,y=1;
for(int i=1;i<=n;fa[i]=0,++i) if(d[i]>d[x]) x=i;
d[x]=0;
dfs(x);
for(int i=1;i<=n;i++) if(d[i]>d[y]) y=i;
for(;y!=x;y=fa[y]) v[y]=1,a[++m]=y;
v[x]=1;
a[++m]=x;
}
void get(int x){
v[x]=1;
for(int i=head[x];i;i=nxt[i]){
int y=to[i],z=len[i];
if(v[y]) continue;
get(y);
f[x]=max(f[x],f[y]+z);
}
}
int main(){
read(n),read(s);
for(int i=1,x,y,z;i<n;++i){
read(x),read(y),read(z);
add(x,y,z),add(y,x,z);
}
pre();
for(int i=1;i<=m;++i) get(a[i]),temp=max(temp,f[a[i]]);
for(int i=m,j=m;i;i--){
while(j && d[a[j]]-d[a[i]]<=s) j--;
ans=min(ans,max(temp,max(d[a[i]],d[a[1]]-d[a[j+1]])));
}
prt(ans);
return 0;
}
染色
数剖题,详见代码。
#include<bits/stdc++.h>
#define lc (x<<1)
#define rc (x<<1|1)
using namespace std;
const int N=100009;
struct node{
int l,r,lcol,rcol,sum,lz;
}tr[N<<2];
int n,m,tot,cnt,L,R;
int head[N],to[N<<1],nxt[N<<1];
int col[N];
int dep[N],siz[N],fa[N],son[N],top[N],seg[N],rev[N];
template<typename T>inline void read(T &a){
T ch=getchar(),f=1;
for(a=0;!isdigit(ch);ch=getchar()) f=ch=='-' ? -1 : f;
for(;isdigit(ch);ch=getchar()) a=(a<<3)+(a<<1)+ch - '0';
a *=f;
}
template<typename T>inline void print(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) print(x / 10);
putchar(x % 10+'0');
}
inline int add(int u,int v){
to[++cnt]=v,nxt[cnt]=head[u],head[u]=cnt;
}
inline void dfs(int x,int f){
dep[x]=dep[f]+1;
siz[x]=1;
fa[x]=f;
for(int i=head[x];i;i=nxt[i]){
int v=to[i];
if(v==f) continue;
if(!dep[v]){
dfs(v,x);
siz[x]+=siz[v];
if(siz[v]>siz[son[x]])
son[x]=v;
}
}
}
inline void dfs2(int x,int f){
if(son[x]){
seg[son[x]]=++tot;
rev[tot]=son[x];
top[son[x]]=top[x];
dfs2(son[x],x);
}
for(int i=head[x];i;i=nxt[i]){
int v=to[i];
if(!top[v]){
top[v]=v;
seg[v]=++tot;
rev[tot]=v;
dfs2(v,x);
}
}
}
inline void build(int x,int l,int r){
tr[x].l=l,tr[x].r=r;
tr[x].lz=-1;
if(l==r){
tr[x].lcol=tr[x].rcol=col[rev[l]];
tr[x].sum=1;
return;
}
int mid=(l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
tr[x].sum=tr[lc].sum+tr[rc].sum;
if(tr[lc].rcol==tr[rc].lcol) tr[x].sum--;
tr[x].lcol=tr[lc].lcol;
tr[x].rcol=tr[rc].rcol;
}
inline void pushdown(int x){
if(tr[x].lz==-1)return;
tr[lc].lz=tr[rc].lz=tr[x].lz;
tr[lc].lcol=tr[lc].rcol=tr[x].lz;
tr[rc].lcol=tr[rc].rcol=tr[x].lz;
tr[lc].sum=tr[rc].sum=1;
tr[x].lz=-1;
}
inline void update(int x,int l,int r,int val){
if(tr[x].l>r || tr[x].r<l) return;
if(tr[x].l>=l && tr[x].r<=r){
tr[x].lz=tr[x].lcol=tr[x].rcol=val;
tr[x].sum=1;
return;
}
pushdown(x);
update(lc,l,r,val);update(rc,l,r,val);
tr[x].sum=tr[lc].sum+tr[rc].sum;
if(tr[lc].rcol==tr[rc].lcol) tr[x].sum--;
tr[x].lcol=tr[lc].lcol;tr[x].rcol=tr[rc].rcol;
}
inline void change(int x,int y,int z){
if(dep[x]<dep[y])swap(x,y);
int fx=top[x],fy=top[y];
while(fx!=fy){
if(dep[fx]<dep[fy]) swap(x,y),swap(fx,fy);
update(1,seg[fx],seg[x],z);
x=fa[top[x]],fx=top[x];
}
if(dep[x]>dep[y]) swap(x,y);
update(1,seg[x],seg[y],z);
}
inline int query(int x,int l,int r){
if(tr[x].l>r || tr[x].r<l) return 0;
if(tr[x].l==l) L=tr[x].lcol;
if(tr[x].r==r) R=tr[x].rcol;
if(tr[x].l>=l && tr[x].r<=r) return tr[x].sum;
pushdown(x);
int ans=query(lc,l,r)+query(rc,l,r);
if(tr[lc].l>r || tr[lc].r<l || tr[rc].l>r || tr[rc].r<l) return ans;
if(tr[lc].rcol==tr[rc].lcol) ans--;
return ans;
}
inline int ask(int x,int y){
int ans=0,lca,tmpx=x,tmpy=y,pre=-1;
int fx=top[x],fy=top[y];
while(fx!=fy){
if(dep[fx]<dep[fy])
swap(x,y),swap(fx,fy);
x=fa[top[x]],fx=top[x];
}
lca=dep[x]>dep[y] ? y : x;
x=tmpx,y=tmpy;
while(top[x]!=top[lca]){
ans+=query(1,seg[top[x]],seg[x]);
if(R==pre) ans--;
pre=L;
x=fa[top[x]];
}
ans+=query(1,seg[lca],seg[x]);
if(R==pre) ans--;
pre=-1;
while(top[y]!=top[lca]){
ans+=query(1,seg[top[y]],seg[y]);
if(R==pre) ans--;
pre=L;
y=fa[top[y]];
}
ans+=query(1,seg[lca],seg[y]);
if(R==pre) ans--;
return ans-1;
}
int a,b,c;
char opt[2];
int main(){
read(n),read(m);
for(int i=1;i<=n;i++) read(col[i]);
for(int i=1;i<n;i++){
read(a),read(b);
add(a,b),add(b,a);
}
dfs(1,0);
seg[1]=rev[1]=top[1]=tot=1;
dfs2(1,0);
build(1,1,n);
while(m--){
scanf("%s",opt);
read(a),read(b);
if(opt[0]=='C')
read(c),change(a,b,c);
else
print(ask(a,b)),putchar('\n');
}
return 0;
}
计算器
快速幂, e x g c d exgcd exgcd, B a b y S t e p , G i a n t S t e p Baby Step,Giant Step BabyStep,GiantStep 板题。
#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void read(T &x){
T ch=getchar();x=0;
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}
template<typename T>inline void prt(T x){
if(x>9) prt(x/10);
putchar(x%10|48);
}
int qpow(int x,int y,int p){
int ret=1;
while(y){
if(y&1) ret=1ll*ret*x%p;
x=1ll*x*x%p;
y>>=1;
}
return ret;
}
int exgcd(int a,int b,int &x,int &y){
if(b==0){x=1,y=0;return a;}
int d=exgcd(b,a%b,x,y);
int z=x;x=y;y=z-y*(a/b);
return d;
}
int BSGS(int a,int b,int p) {
map<int,int> hash;
hash.clear();
int t=(int)sqrt(p)+1;
for(int i=0;i<t;i++) {
int val=1ll*b*qpow(a,i,p)%p;
hash[val]=i;
}
a=qpow(a,t,p);
if(!a) return b?-1:1;
for(int i=0;i<=t;i++) {
int val=qpow(a,i,p);
int j=hash.find(val)==hash.end() ? -1:hash[val];
if(j>=0 && i*t>=j) return i*t-j;
}
return -1;
}
int T,K,y,z,p;
int main(){
for(read(T),read(K);T--;){
int x,t,d;
read(y),read(z),read(p);
if(K==1) prt(qpow(y%p,z%(p-1),p)),puts("");
if(K==2){
d=exgcd(y,p,x,t);
if(z%d) puts("Orz, I cannot find x!");
else prt((1ll*x*z/d%p+p)%p),puts("");
}
if(K==3){
d=BSGS(y,z,p);
if(d==-1) puts("Orz, I cannot find x!");
else prt(d),puts("");
}
}
}