QOJ-2901 Hopscotch 500
题意:
给定n*n的棋盘,每一个格有对应的值,玩家从1跳到k,每一步的代价是,问总的代价的最小值。
题解思路:
从p状态转移到p+1状态,假设p状态我们已知到每一行和每一列的最小代价,我们去算p+1合法状态每一个点从每一行每一列转移来的代价并且更新。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fi first
#define se second
#define inf 0x3f3f3f3f3f3f3f
typedef long long ll;
int a[510][510];
//int dpx[510],dpy[510],nx[510],ny[510];
vector<pair<int,int>>v[251000];
int f(int x,int y) {
return (x-y)*(x-y);
}
int n,k;
void solve() {
cin>>n>>k;
for(int i=1; i<=n; i++) {
for(int j=1,x; j<=n; j++) {
cin>>x;
v[x].push_back({i,j});
}
}
vector<int>dpx(n+1,inf),dpy(n+1,inf);
for(auto vi:v[1]) {
int x=vi.fi;
int y=vi.se;
dpx[x]=dpy[y]=0;
}
for(int i=2; i<=k; i++) {
vector<int>nx(n+1,inf),ny(n+1,inf);
for(auto vi:v[i]) {
int x=vi.fi;
int y=vi.se;
int mn=inf;
for(int j=1; j<=n; j++) {
mn=min(mn,dpx[j]+f(j,x));
mn=min(mn,dpy[j]+f(j,y));
}
nx[x]=min(mn,nx[x]);
ny[y]=min(mn,ny[y]);
}
dpx=nx;
dpy=ny;
}
int ans=inf;
for(int i=1; i<=n; i++) {
ans=min({dpx[i],dpy[i],ans});
}
if(ans==inf)cout<<-1<<'\n';
else cout<<ans<<'\n';
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t=1;
// cin>>t;
while(t--)solve();
return 0;
}
A National Pandemic
题意:树图,有三种操作:操作1 在x点爆发w严重值,其他所有点受w-dis(i,x)的严重影响。操作2 x点严重值 与0 取min。 操作3询问 x点严重值。
解题思路:
树链剖分+树上差分的操作。
做题时处理操作2出现问题,把pre+=w改成pre=w就过了...
补树链剖分的知识:
题目种的具体操作:
ac代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10;
#define int long long
#define lc (p<<1)
#define rc (p<<1|1)
int w[N];
vector<int> e[N];
int fa[N],dep[N],sz[N],son[N];
int top[N],id[N],nw[N],cnt;
struct tree {
int l,r;
int add,sum;
} tr[4*N];
int n,a[N],c[N];
void dfs1(int u,int father) {
fa[u]=father,dep[u]=dep[father]+1,sz[u]=1;
for(int v:e[u]) {
if(v==father)continue;
dfs1(v,u);
sz[u]+=sz[v];
if(sz[son[u]]<sz[v])son[u]=v;
}
}
void dfs2(int u,int t) {//树链剖分
top[u]=t,id[u]=++cnt,nw[cnt]=w[u];
if(!son[u])return ;
dfs2(son[u],t);
for(int v:e[u]) {
if(v==fa[u]||v==son[u])continue;
dfs2(v,v);
}
}
void pushup(int p) {
tr[p].sum=tr[lc].sum+tr[rc].sum;
}
void pushdown(int p) {
if(tr[p].add) {
tr[lc].sum+=tr[p].add*(tr[lc].r-tr[lc].l+1);
tr[rc].sum+=tr[p].add*(tr[rc].r-tr[rc].l+1);
tr[lc].add+=tr[p].add;
tr[rc].add+=tr[p].add;
tr[p].add=0;
}
}
void build(int p,int l,int r) {
tr[p]= {l,r,0,nw[r]};
if(l==r)return ;
int mid=l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
pushup(p);
}
void update(int p,int l,int r,int k) {
if(l<=tr[p].l&&r>=tr[p].r) {
tr[p].add+=k;
tr[p].sum+=k*(tr[p].r-tr[p].l+1);
return ;
}
pushdown(p);
int mid=tr[p].l+tr[p].r>>1;
if(l<=mid)update(lc,l,r,k);
if(r>mid)update(rc,l,r,k);
pushup(p);
}
void update_path(int u,int v,int k) {
while(top[u]!=top[v]) {
if(dep[top[u]<dep[top[v]]])swap(u,v);
update(1,id[top[u]],id[u],k);
u=fa[top[u]];
}
if(dep[u]<dep[v])swap(u,v);
update(1,id[v],id[u],k);
}
int query(int p,int l,int r) {
if(l<=tr[p].l&&r>=tr[p].r)return tr[p].sum;
pushdown(p);
int mid=tr[p].l+tr[p].r>>1;
int res=0;
if(l<=mid)res+=query(lc,l,r);
if(r>mid)res+=query(rc,l,r);
return res;
}
int query_path(int u,int v) {
int res=0;
while(top[u]!=top[v]) {
if(dep[top[u]]<dep[top[v]])swap(u,v);
res+=query(1,id[top[u]],id[u]);
u=fa[top[u]];
}
if(dep[u]<dep[v])swap(u,v);
res+=query(1,id[v],id[u]);
return res;
}
int pre[N];
void solve() {
int n,m;
cin>>n>>m;
for(int i=1; i<=n; i++) {
e[i].clear();
w[i]=fa[i]=dep[i]=sz[i]=son[i]=0;
top[i]=id[i]=nw[i]=cnt=a[i]=c[i]=pre[i]=0;
}
for(int i=1; i<n; i++) {
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
int cnt=0,cur=0;
while(m--) {
int op;
cin>>op;
if(op==1) {
int x,w;
cin>>x>>w;
cur+=w-(dep[x]-dep[1]);
cnt++;
update_path(1,x,2);
update_path(1,1,-2);
} else {
int x;
cin>>x;
int w=query_path(1,x);
w=w+cur-cnt*(dep[x]-dep[1]);
if(op==3)cout<<w-pre[x]<<'\n';
else {
if(w>0) {
pre[x]=w;
}
}
}
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t=1;
cin>>t;
while(t--)
solve();
return 0;
}
Red Black Grid
哥们有史以来wa的最多的一次,太难写了
n<=3时打表,
其余情况,分v2,v3,v4,自己悟一下为什么这么分,然后尽量让v4多分一点,v3调节奇偶,剩下的给v2,可以证明1或者2n(n-1)-1时无解,其它情况都是有解的。
ad代码(较丑)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int long long
const int N=1e5+10;
int n, k;
vector<int>ans;
bool vis[1015][1015];
bool fz[1015][1015];
void solve() {
cin>>n>>k;
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
vis[i][j]=0;
fz[i][j]=0;
}
}
ll sum=2*n*(n-1);
int res;
if(k>sum||k==1||k==sum-1)cout<<"Impossible\n";
//
else if(n==1) {
if(k==0) {
cout<<"Possible\n";
cout<<"R\n";
} else {
cout<<"Impossible\n";
}
} else if(n==2) {
if(k==0) {
cout<<"Possible\n";
cout<<"RR\nRR\n";
} else if(k==1||k==3) {
cout<<"Impossible\n";
} else if(k==2) {
cout<<"Possible\n";
cout<<"BB\nRR\n";
} else if(k==4) {
cout<<"Possible\n";
cout<<"RB\nBR\n";
}
} else if(n==3) {/
if(k==1||k==11)cout<<"Impossible\n";
else {
cout<<"Possible\n";//
if(k==0) { /
cout<<"RRR\nRRR\nRRR\n";
} else if(k==2) {
cout<<"RBB\nBBB\nBBB\n";
} else if(k==3) {
cout<<"BRB\nBBB\nBBB\n";
} else if(k==4) {
cout<<"BBB\nBRB\nBBB\n";
} else if(k==5) {
cout<<"RBB\nBBB\nBRB\n";
} else if(k==6) {
cout<<"BRB\nBBB\nBRB\n";
} else if(k==7) {
cout<<"BRB\nBBB\nRBR\n";
} else if(k==8) {
cout<<"RBR\nBBB\nRBR\n";
} else if(k==9) {
cout<<"BRB\nRBR\nBBB\n";
} else if(k==10) {
cout<<"RBR\nBRB\nRBB\n";
} else if(k==12) {
cout<<"RBR\nBRB\nRBR\n";
}
}
}
else {
vector<pair<int,int>>v2,v3,v4;
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
if((i+j)%2==0) {
if((i==1||i==n)&&(j==1||j==n)) {
v2.push_back({i,j});
} else if((i==1||i==n)||(j==1||j==n))v3.push_back({i,j});
else v4.push_back({i,j});
}
}
}
int c4=0,c2=0,c3=0;
while(k>=4) {
c2++;
k-=2;
}
if(k==3) {
c3++;
k-=3;
} else if(k==2) {
c2++;
k-=2;
}
int s2to3=c2*2/6;
int pp=((int)v3.size()-c3)/2;
int t=min(pp,s2to3)*2;
c3+=t;
c2-=t*3/2;
int s2to4=min(c2*2/4,(int)v4.size());
c4=s2to4;
c2-=c4*4/2;
for(int i=0; i<c2; i++) {
int x=v2[i].first;
int y=v2[i].second;
fz[x][y]=1;
}
for(int i=0; i<c3; i++) {
int x=v3[i].first;
int y=v3[i].second;
fz[x][y]=1;
}
for(int i=0; i<c4; i++) {
int x=v4[i].first;
int y=v4[i].second;
fz[x][y]=1;
}
cout<<"Possible\n";
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
if(fz[i][j]==1)cout<<"R";
else cout<<"B";
}
cout<<'\n';
}
}
}
/*
3 6
3 1
6 4
6 2
9 4
*/
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t=1000;
cin>>t;
while(t--)solve();
return 0;
}
Sereja and Brackets
2000的线段树题,括号匹配问题,当前区间匹配数等于左右区间各自匹配好的加起来,以及(左区间未匹配好的和右区间未匹配好的)取min,难点在于写法。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define debugs(x,y) cerr<<#x<<" : "<<x<<" "<<#y<<" "<<y<<endl
#define int long long
#define ls ((p<<1))
#define rs ((p<<1)|1)
const int N=1e6+10;
int n,m,a[N];
string str;
struct node {
int al,ar;
int sum;
} tr[N<<3];
void pushup(int p) {
int res=min(tr[ls].al,tr[rs].ar);
tr[p].sum=tr[ls].sum+tr[rs].sum+res;
tr[p].al=tr[ls].al+tr[rs].al-res;
tr[p].ar=tr[ls].ar+tr[rs].ar-res;
}
void build(int p,int l,int r) {
if(l==r) {
tr[p].sum=0;
if(a[l]==1) {
tr[p].al=1;
} else tr[p].ar=1;
return;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(p);
}
node query(int p,int l,int r,int x,int y) {
if(l>=x&&r<=y) {
return {tr[p].al,tr[p].ar,tr[p].sum};
}
int mid=(l+r)>>1;
int res=0;
int resl=0,resr=0;
node Rl,rr;
int dd=0;
if(x<=mid) {
Rl=query(ls,l,mid,x,y),res+=Rl.sum;
}
if(y>mid) {
rr=query(rs,mid+1,r,x,y),res+=rr.sum;
}
if(x<=mid&&y>mid) {
dd=min(Rl.al,rr.ar);
resl=Rl.al+rr.al-dd;
resr=Rl.ar+rr.ar-dd;
res=res+dd;
}else if(x<=mid){
resl=Rl.al;
resr=Rl.ar;
}
else if(y>mid){
resl=rr.al;
resr=rr.ar;
}
return {resl,resr,res};
}
void solve() {
cin>>str;
for(int i=0; i<str.size(); i++) {
if(str[i]=='(')a[i+1]=1;
else a[i+1]=-1;
}
n=str.size();
build(1,1,n);
cin>>m;
// cout<<tr[1].sum<<endl;
for(int i=1,x,y; i<=m; i++) {
cin>>x>>y;
cout<<query(1,1,n,x,y).sum*2<<'\n';
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t=1;
// cin>>t;
while(t--)solve();
return 0;
}