2017/8/7 離線賽
T1 Codechef JAN17 務農政策
這題的解法很好想,就是每次詢問時列舉每個矩形,然後求出最小的花費, 每個矩形的終態就是這個矩形中最高的那塊,我們只要用二維字首和維護每個矩形的權值和,再求出每個矩形中最大的權值即可。難點在怎麼求每個矩形的最大權值,這是一個二維的部分最大值。由於之前寫了球染色這道題,所以腦子裡印象比較深刻,我們立馬想用單調佇列求出這個最大值,但是發現二維的不好維護,我就先維護了每一行的最大值,這樣把一段區間加在一個點上,再豎著來一遍,就求出二維的最大值了。
typedef pair<int,int> P;
int n,m,mi=2e9,mx;
int h[M][M];
ll sum[M][M];
int Max[M][M];
P que[M];
int L,R;
int T;
int main(){
int a,b;
Rd(n);Rd(m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
Rd(h[i][j]);
mi=min(mi,h[i][j]);
mx=max(mx,h[i][j]);
sum[i][j]=sum[i-1][j-1]+sum[i][j-1]-sum[i-1][j-1]+sum [i-1][j]-sum[i-1][j-1]+h[i][j];
}
Rd(T);
while(T--){
memset(Max,0,sizeof(Max));
ll ans=2e18;
Rd(a);Rd(b);
for(int i=1;i<=n;i++){
L=R=0;
for(int j=1;j<=m;j++){
while(L<R&&que[R-1].first<h[i][j])R--;
que[R++]=P(h[i][j],j);
while (L<R&&j-que[L].second>=b)L++;
Max[i][j]=que[L].first;
}
}
for(int j=b;j<=m;j++){
L=R=0;
for(int i=1;i<=n;i++){
while(L<R&&que[R-1].first<Max[i][j])R--;
que[R++]=P(Max[i][j],i);
while(L<R&&i-que[L].second>=a)L++;
Max[i][j]=que[L].first;
}
}
for(int i=a;i<=n;i++)
for(int j=b;j<=m;j++)//列舉右下角
ans=min(ans,1LL*a*b*Max[i][j]-(sum[i][j]-sum[i-a][j]-sum[i][j-b]+sum[i-a][j-b]));
Pt(ans);
putchar('\n');
}
return 0;
}
T2 Codechef JUNE16 刷副本
這道題的難點就在如何求首位了,考試的時候我敲了個高精,然後手賤陣列開了50000,每次定義一次要
我們只要處理出每個數的
接下來是查詢和更新操作了。對於查詢,我們事先預處理出每種
int fast(int a,int p){
int res=1;
while(p){
if(p&1)res=1LL*res*a%P;
a=1LL*a*a%P;
p>>=1;
}
return res;
}
int n,q;
int A[M];
int fac[M];
double sum[M];
vector<int>son[M];
int main(){
int opr,x,f;
Rd(n);
for(int i=0;i<n;i++)Rd(A[i]);
for(int i=1;i<=n;i++){
fac[i]=1;
for(int j=i;j<n;j+=i){
fac[i]=1LL*fac[i]*A[j]%P;
sum[i]+=log10(A[j]);
son[j].push_back(i);
}
}
Rd(q);
while(q--){
Rd(opr);
if(opr==1){
Rd(x);Rd(f);x--;
if(x){
int pre=A[x];
double t=log10(pre);
int tt=fast(pre,P-2);
double ttt=log10(f);
for(int i=0;i<son[x].size();i++){
int v=son[x][i];
sum[v]-=t;
sum[v]+=ttt;
fac[v]=1LL*fac[v]*tt%P*f%P;
}
}
A[x]=f;
}else{
Rd(x);
int res=1LL*fac[x]*A[0]%P;
double fi=sum[x]+log10(A[0]);
int ans=(int)pow(10,fi-floor(fi)+eps);
if(ans==10)ans=1;
Pt(ans);
putchar(' ');
Pt(res);
putchar('\n');
}
}
return 0;
}
T3 USACO 2017 Open Platinum 聖盃戰爭
唉,這題考試時不知道怎麼想的,敲了個
發現了這個性質,題目就好想了,我們不妨以1為根,對每個點建樹,存下這個點到達每種顏色兒子的花費,由於記憶體開不下,我們可以採用動態造節點的方式,因為在最大資料中一個點能用到的兒子最多隻有10個。對於一個節點的貢獻,只要
#include<set>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#define M 200005
#define oo 2000000000
using namespace std;
template <class T>
inline void Rd(T &res){
char c;res=0;int k=1;
while(c=getchar(),c<48&&c!='-');
if(c=='-'){k=-1;c='0';}
do{
res=(res<<3)+(res<<1)+(c^48);
}while(c=getchar(),c>=48);
res*=k;
}
template <class T>
inline void Pt(T res){
if(res<0){
putchar('\n');
res=-res;
}
if(res>=10)Pt(res/10);
putchar(res%10+48);
}
struct ED{
int a,b,w;
bool operator <(const ED &tmp)const{
return w<tmp.w;
}
}E[M<<1];
struct edge{
int v,nxt,cost;
}e[M<<1];
multiset<int>ans,s[M<<2];
int n,m,K,Q;
int A[M],fa[M],pa[M],res[M],la[M];//pa存樹上的father
int rt[M],num[M*60],sz,lr[M*60],rr[M*60];
int id[M*60],ct;
int head[M],edgecnt;
int get_fa(int v){
if(fa[v]==v)return v;
return fa[v]=get_fa(fa[v]);
}
bool same(int u,int v){
return get_fa(u)==get_fa(v);
}
void merge(int u,int v){
int px=get_fa(u);
int py=get_fa(v);
fa[py]=px;
}
void add_edge(int u,int v,int cost){
e[++edgecnt].v=v;e[edgecnt].cost=cost;e[edgecnt].nxt=head[u];head[u]=edgecnt;
}
void up(int p){
num[p]=min(num[lr[p]],num[rr[p]]);
}
int query(int p,int L,int R,int l,int r){
if(!p||l>r)return oo;
if(l==L&&r==R)return num[p];
int mid=(L+R)>>1;
if(r<=mid)return query(lr[p],L,mid,l,r);
if(l>mid)return query(rr[p],mid+1,R,l,r);
return min(query(lr[p],L,mid,l,mid),query(rr[p],mid+1,R,mid+1,r));
}
void update(int &p,int L,int R,int x,int w,bool f){
if(!p){p=++sz;num[p]=oo;}
if(L==R){
if(!id[p])id[p]=++ct;
int now=id[p];
if(f)s[now].insert(w);
else s[now].erase(s[now].find(w));
if(s[now].size())num[p]=*(s[now].begin());
else num[p]=oo;
return;
}
int mid=(L+R)>>1;
if(x<=mid)update(lr[p],L,mid,x,w,f);
else update(rr[p],mid+1,R,x,w,f);
up(p);
}
void dfs(int x,int t){
pa[x]=t;
for(int i=head[x];~i;i=e[i].nxt){
int v=e[i].v;
if(v==t)continue;
dfs(v,x);
res[v]=e[i].cost;
update(rt[x],1,K,A[v],e[i].cost,1);
}
if(rt[x]){
la[x]=min(query(rt[x],1,K,1,A[x]-1),query(rt[x],1,K,A[x]+1,K));
ans.insert(la[x]);
}
}
void Init(){
memset(head,-1,sizeof(head));
memset(pa,-1,sizeof(pa));
num[0]=oo;
sort(E+1,E+m+1);
for(register int i=1;i<=m;++i){
int u=E[i].a,v=E[i].b;
if(!same(u,v)){
add_edge(u,v,E[i].w);
add_edge(v,u,E[i].w);
merge(u,v);
}
}
dfs(1,-1);
}
int main(){
int x,k;
Rd(n);Rd(m);Rd(K);Rd(Q);
for(int i=1;i<=m;i++){
Rd(E[i].a);Rd(E[i].b);Rd(E[i].w);
}
for(int i=1;i<=n;i++){
Rd(A[i]);
fa[i]=i;
}
Init();
while(Q--){
Rd(x);Rd(k);
if(k!=A[x]){
if(rt[x]){
ans.erase(ans.find(la[x]));
la[x]=min(query(rt[x],1,K,1,k-1),query(rt[x],1,K,k+1,K));
ans.insert(la[x]);
}
if(x!=1){
int f=pa[x];
ans.erase(ans.find(la[f]));
update(rt[f],1,K,A[x],res[x],0);
update(rt[f],1,K,k,res[x],1);
la[f]=min(query(rt[f],1,K,1,A[f]-1),query(rt[f],1,K,A[f]+1,K));
ans.insert(la[f]);
}
A[x]=k;
}
Pt(*(ans.begin()));
putchar('\n');
}
return 0;
}
T2的失算讓我對