2018.9.17 離線賽 by ShimaKZ&EastKing
阿新 • • 發佈:2018-12-10
T1——faker(3920)
Description:
有一個長度為的初始為空的序列{},有m個操作,每個操作有: 1. ,對區間加. 2. ,重複操作. 求操作完後序列{}.
Solution:
- 不難發現操作2是對於前面的操作,那麼就要從後往前執行操作2.
- 那麼這樣就可以記錄下對於每個操作的次數.
- 那麼對於操作1就是加上當前的即可.
- 這樣,就是字尾遍歷的.
Code:
#include<bits/stdc++.h> using namespace std; #define REP(i,f,top)for(int i=(f),i##_end_=(top);i<=i##_end_;++i) #define SREP(i,f,top)for(int i=(f),i##_end_=(top);i<i##_end_;++i) #define DREP(i,f,top)for(int i=(f),i##_end_=(top);i>=i##_end_;--i) #define db double #define ll long long #define INF 0x3f3f3f3f #define inf 0x3f3f3f3f3f3f3f #define MINF 0xc0c0c0c0 #define Sz(A) sizeof(A) #define mcl(A,b) memset(A,b,Sz(A)) #define mcp(A,b) memcpy(A,b,Sz(b)) #define pb push_back #define fi first #define se second template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;} template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;} typedef pair<int,int>PII; template<class T>inline void Rd(T &x){ x=0;char c;int f=1; while((c=getchar())<48)if(c=='-')f=-1; do x=(x<<1)+(x<<3)+(c^48); while((c=getchar())>47); x*=f; } #define N 1000010 #define mod 1000000007 int n,m; struct ask{ int op,l,r; }Q[N]; struct p2{ int cnt[N],add[N]; void solve(){ cnt[m]=1; DREP(i,m,1){ cnt[i]=(cnt[i]+cnt[i+1])%mod; if (Q[i].op==1) { add[Q[i].l]=(add[Q[i].l]+cnt[i])%mod; add[Q[i].r+1]=(add[Q[i].r+1]+mod-cnt[i])%mod; } else { cnt[Q[i].r]=(cnt[Q[i].r]+cnt[i])%mod; cnt[Q[i].l-1]=(cnt[Q[i].l-1]+mod-cnt[i])%mod; } } int ans=0; REP(i,1,n){ ans=(ans+add[i])%mod; printf("%d%c",ans,i==n?'\n':' '); } } }p2; int main(){ // freopen("faker.in","r",stdin); // freopen("faker.out","w",stdout); Rd(n),Rd(m); REP(i,1,m)Rd(Q[i].op),Rd(Q[i].l),Rd(Q[i].r); p2.solve(); return 0; }
T2——poi(3921)
Description:
有n個排成一行的島嶼,有在這些島嶼上建立燈塔.需要滿足,特別地,.而你可以強行將一個島嶼的變小,代價即為減小的問建立~的最小代價.
Solution:
- 首先看題,就可以判斷是一道經典的.
- 那麼我們先來分析一下問題的本質.
- 對於第個燈塔來說,第和一定不是燈塔.
- 而我們不難發現對於第個島嶼來說,我們只關心第,個.
- 若我們做從左到右的遞推,即對於第個島嶼來說,只關心第,個.(猜測之後一定會滾動陣列優化一下)
- 對於題目問的是~.這固然不能單獨解決.一定是問題的其中一維.
- 那麼我們就不難想到一個的狀態:表示前個島嶼中建立了個燈塔的最小代價.
- k=0表示在,處都不建塔.
- k=1表示在處建塔.
- k=2表示在處建塔.
- 然後再將其分類討論一下,不難轉移.
Code:
#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,top)for(int i=(f),i##_end_=(top);i<=i##_end_;++i)
#define SREP(i,f,top)for(int i=(f),i##_end_=(top);i<i##_end_;++i)
#define DREP(i,f,top)for(int i=(f),i##_end_=(top);i>=i##_end_;--i)
#define db double
#define ll long long
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define MINF 0xc0c0c0c0
#define Sz(A) sizeof(A)
#define mcl(A,b) memset(A,b,Sz(A))
#define mcp(A,b) memcpy(A,b,Sz(b))
#define pb push_back
#define fi first
#define se second
template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
typedef pair<int,int>PII;
template<class T>inline void Rd(T &x){
x=0;char c;int f=1;
while((c=getchar())<48)if(c=='-')f=-1;
do x=(x<<1)+(x<<3)+(c^48);
while((c=getchar())>47);
x*=f;
}
#define N 5002
int n;
int A[N];
struct p100{
int dp[3][N][2];
void solve(){
A[++n]=0;
mcl(dp,INF);
dp[1][0][0]=0;
dp[0][0][0]=0;
int f=1;
REP(i,2,n){
f=(f+1)%3;
mcl(dp[f],INF);
REP(j,0,n/2){
dp[f][j][0]=min(dp[(f+2)%3][j][0],dp[(f+2)%3][j][1]);
if(j>=1){
chkmin(dp[f][j][1],dp[(f+1)%3][j-1][0]+
max(0,A[i]-(A[i-1]-1))+max(0,A[i-2]-(A[i-1]-1)));
}
if(j>=1 && i>=3){
chkmin(dp[f][j][1],dp[(f+1)%3][j-1][1]+
max(0,A[i]-(A[i-1]-1))+max(0,min(A[i-2],A[i-3]-1)-(A[i-1]-1)));
}
}
}
REP(i,1,n/2) printf("%d ",min(dp[f][i][0],dp[f][i][1]));
}
}p2;
int main(){
// freopen("poi.in","r",stdin);
// freopen("poi.out","w",stdout);
Rd(n);
REP(i,1,n)Rd(A[i]);
p2.solve();
return 0;
}
T3——azur(3922)
Description:
有一個的網格圖,每條邊都有邊權.接下來有個操作:
- 在 到的最短路徑上的各點的點權加.
- 詢問的點權.
Solution:
- 因為操作需要修改一個最短路徑.每次求一次最短路顯然不現實.
- 又因為邊權不變,那麼考慮預處理出每個點的最短路徑樹.
- 但顯然我們不能做棵樹,再來觀察資料範圍,發現非常小.
- 這說明一定跟區間搭上關係.那麼我們就可以考慮合併一些贅餘的樹.
- 即儘可能的少建一些樹.不難推出.只需要棵樹就可以了(合併之後).
- 那麼再來看操作,我們再區間上看,它的最短路徑樹必須會經過一個區間[l,r]的mid,即必經過點,即,在以點為根的子樹下.
- 即可以做樹上差分.
- 又因為是單點查詢.那麼就可以單點累加下去即可.
- 而對於修改和查詢的樹上,都需要分治來找.
Code:
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,top)for(int i=(f),i##_end_=(top);i<=i##_end_;++i)
#define SREP(i,f,top)for(int i=(f),i##_end_=(top);i<i##_end_;++i)
#define DREP(i,f,top)for(int i=(f),i##_end_=(top);i>=i##_end_;--i)
#define db double
#define ll long long
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define MINF 0xc0c0c0c0
#define Sz(A) sizeof(A)
#define mcl(A,b) memset(A,b,Sz(A))
#define mcp(A,b) memcpy(A,b,Sz(b))
#define pb push_back
#define fi first
#define se second
template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
typedef pair<int,int>PII;
template<class T>inline void Rd(T &x){
x=0;char c;int f=1;
while((c=getchar())<48)if(c=='-')f=-1;
do x=(x<<1)+(x<<3)+(c^48);
while((c=getchar())>47);
x*=f;
}
#define N 300010
#define M 20
int n,m,q;
int qwq,head[N];
struct edge{
int to,nxt;
ll cost;
}E[N*10];
inline void addedge(int x,int y,ll z){E[qwq]=(edge){y,head[x],z};head[x]=qwq++;}
inline int getid(int x,int y){return (x-1)*n+y;}
struct p30{
ll val[N];
ll dis[M];
bool vis[M];
int stk[M],top;
int S,T;
queue<int>Q;
void SPFA(){
while(!Q.empty())Q.pop();
mcl(dis,INF);
Q.push(T);
vis[T]=1;
dis[T]=0;
while(!Q.empty()){
int x=Q.front();Q.pop();
vis[x]=0;
for(int i=head[x];~i;i=E[i].nxt){
int y=E[i].to;
if(chkmin(dis[y],dis[x]+E[i].cost)){
if(!vis[y]){
vis[y]=1;
Q.push(y);
}
}
}
}
}
struct Anode{
int to;
ll d,all;
bool operator<(const Anode &_)const{
return all==_.all?d>_.d:all>_.all;
}
};
priority_queue<Anode>Star;
void Astar(){
while(!Star.empty())Star.pop();
Star.push((Anode){S,0,dis[S]});
while(!Star.empty()){
Anode now=Star.top();Star.pop();
int x=now.to;
stk[++top]=x;
if(x==T)break;
for(int i=head[x];~i;i=E[i].nxt){
int y=E[i].to;
Star.push((Anode){y,now.d+E[i].cost,now.d+E[i].cost+dis[y]});
}
}
}
void solve(){
mcl(head,-1);
SREP(i,1,m){
REP(j,1,n){
ll x;Rd(x);
// printf("i=%d j=%d id1=%d id2=%d\n",i,j,getid(i,j),getid(i+1,j));
addedge(getid(i,j),getid(i+1,j),x);
addedge(getid(i+1,j),getid(i,j),x);
}
}
REP(i,1,m){
SREP(j,1,n){
ll x;Rd(x);
// printf("i=%d j=%d id1=%d id2=%d\n",i,j,getid(i,j),getid(i,j+1));
addedge(getid(i,j),getid(i,j+1),x);
addedge(getid(i,j+1),getid(i,j),x);
}
}
int op,x1,y1,x2,y2;ll c;
while(q--){
Rd(op),Rd(x1),Rd(y1);
if(op==1){
Rd(x2),Rd(y2),Rd(c);
top=0;
S=getid(x1,y1),T=getid(x2,y2);
SPFA();
Astar();
// Dij();
REP(i,1,top)val[stk[i]]+=c;
}
else printf("%lld\n",val[getid(x1,y1)]);
}
}
}p1;
struct p50{
#define lson L,mid,p<<1
#define rson mid+1,R,p<<1|1
struct node{
int L,R;
ll sum;
}tree[100010<<2];
void build(int L,int R,int p){
tree[p].L=L,tree[p].R=R;
tree[p].sum=0;
if(L==R)return;
int mid=(L+R)>>1;
build(lson),build(rson);
}
void update(int L,int R,int p,ll v){
if(tree[p].L==L && tree[p].R==R){
tree[p].sum+=v;
return;
}
int mid=(tree[p].L+tree[p].R)>>1;
if(R<=mid)update(L,R,p<<1,v);
else if(L>mid)update(L,R,p<<1|1,v);
else update(lson,v),update(rson,v);
}
ll query(int p,int x){
if(tree[p].L==tree[p].R)return tree[p].sum;
int mid=(tree[p].L+tree[p].R)>>1;
if(x<=mid)return tree[p].sum+query(p<<1,x);
else return tree[p].sum+query(p<<1|1,x);
}
void solve(){
SREP(i,1,n){
ll x;Rd(x);
}
build(1,n,1);
int op,x1,y1,x2,y2;ll c;
while(q--){
Rd(op),Rd(x1),Rd(y1);
if(op==1){
Rd(x2),Rd(y2),Rd(c);
if(y1>y2)swap(y1,y2);
update(y1,y2,1,c);
}
else printf("%lld\n",query(1,y1));
}
}
}p2;
ll sum[N*M*5],*tmp=sum;
int pre[M][4][N];
ll dis[M][4][N];
struct p100{
vector<int>V[N];
int id[4][N],sz[4][N];
ll *rt[4][N];
int Lt[M][4][N],Rt[M][4][N];
int D;
ll val[N];
ll mn,res;
#define lowbit(x) (x&-x)
void add(ll *bit,int n,int x,ll v){
while(x<=n){
bit[x]+=v;
x+=lowbit(x);
}
}
ll query(ll *bit,int x){
ll res=0;
while(x){
res+=bit[x];
x-=lowbit(x);
}
return res;
}
struct node{
int x;
ll d;
bool operator>(const node&_)const{
return d>_.d;
}
};
// priority_queue<node>Q;
struct Heap_Sort {
node Heap[N];
int size;
void down(int k) {
while(2*k<=size) {
int a=2*k;
if(a+1<=size && Heap[a]>Heap[a+1])a++;
if(Heap[k]>Heap[a])swap(Heap[k],Heap[a]);
else break;
k=a;
}
}
node top() {return Heap[1];}
void pop() {
Heap[1]=Heap[size--];
down(1);
}
void up(int k) {
while(k>1) {
int a=k/2;
if(Heap[a]>Heap[k])swap(Heap[k],Heap[a]);
else break;
k=a;
}
}
bool empty(){return !size;}
void push(node x) {
Heap[++size]=x;
up(size);
}
void clear(){
size=0;
}
}Q;
void dfs(int x,int *Lt,int *Rt,int&sz){
Lt[x]=++sz;
SREP(i,0,V[x].size()) dfs(V[x][i],Lt,Rt,sz);
Rt[x]=sz;
}
void Dijkstra(int dep,int x,int y,int l,int r){
ll *dis=::dis[dep][x];
int *pre=::pre[dep][x];
SREP(i,0,m) REP(j,l,r){
dis[id[i][j]]=inf;
pre[id[i][j]]=-1;
V[id[i][j]].clear();
}
dis[id[x][y]]=0;
Q.push((node){id[x][y],0});
while(!Q.empty()){
node now=Q.top();Q.pop();
if(dis[now.x]!=now.d)continue;
for(int i=head[now.x];~i;i=E[i].nxt){
int y=E[i].to;
if(chkmin(dis[y],dis[now.x]+E[i].cost)){
pre[y]=now.x;
Q.push((node){y,dis[y]});
}
}
}
SREP(i,0,m) REP(j,l,r) if(~pre[id[i][j]]) V[pre[id[i][j]]].pb(id[i][j]);
dfs(id[x][y],Lt[dep][x],Rt[dep][x],sz[x][y]);
rt[x][y]=tmp;
tmp+=sz[x][y]+1;
}
void build(int L,int R,int dep){
if(L>R)return;
int mid=(L+R)>>1;
SREP(i,0,m) Dijkstra(dep,i,mid,L,R);
build(L,mid-1,dep+1);
build(mid+1,R,dep+1);
}
int x,y,x1,Y1,x2,y2;
void update(int L,int R,int dep){
if(L>R)return;
int mid=(L+R)>>1;
SREP(i,0,m){
if(chkmin(mn,dis[dep][i][id[x1][Y1]]+dis[dep][i][id[x2][y2]])){
D=dep;
x=i;
y=mid;
}
}
if(Y1<mid && y2<mid) update(L,mid-1,dep+1);
if(Y1>mid && y2>mid) update(mid+1,R,dep+1);
}
void divide(int L,int R,int dep){
if(L>R)return;
int mid=(L+R)>>1;
SREP(i,0,m){
res+=query(rt[i][mid],Rt[dep][i][id[x][y]]);
res-=query(rt[i][mid],Lt[dep][i][id[x][y]]-1);
}
if(y<mid) divide(L,mid-1,dep+1);
else if(y>mid) divide(mid+1,R,dep+1);
}
void solve(){
mcl(head,-1);
int num=0;
SREP(i,0,m) REP(j,1,n)id[i][j]=++num;
SREP(i,0,m-1) REP(j,1,n){
ll w;Rd(w);
addedge(id[i][j],id[i+1][j],w);
addedge(id[i+1][j],id[i][j],w);
}
SREP(i,0,m) SREP(j,1,n){
ll w;Rd(w);
addedge(id[i][j],id[i][j+1],w);
addedge(id[i][j+1],id[i][j],w);
}
build(1,n,0);
while(q--){
int op;ll c;
Rd(op);
if(op==1){
Rd(x1),Rd(Y1),Rd(x2),Rd(y2),Rd(c);
x1--,x2--;
mn=inf;
update(1,n,0);
add(rt[x][y],sz[x][y],Lt[D][x][id[x1][Y1]],c);
add(rt[x][y],sz[x][y],Lt[D][x][id[x2][y2]],c);
val[id[x][y]]-=c;
}
else{
Rd(x),Rd(y);
x--;
res=val[id[x][y]];
divide(1,n,0);
printf("%lld\n",res);
}
}
}
}p3;
int main(){
// freopen("azur.in","r",stdin);
// freopen("azur.out","w",stdout);
Rd(m),Rd(n),Rd(q);
// if(m==1)p2.solve();
// else if(n<=1000 && q<=1000)p1.solve();
// else
p3.solve();
return 0;
}
總結:
- 送分題+題+資料結構題.還是比較標準的一套.
- 但T3的切分以及碼量問題,導致選手們都自閉…
- 但考場上自己也是對這個記憶體範圍沒感覺,沒想到此題要建樹.
- 以及T2的分類討論和debug花了較長時間…
- 還是有待提高的.
- 評價:較毒瘤出題人.