2016年7月28日 星期四

(UVA) 11297 - Census [樹套樹 求 max, min]

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=&problem=2272&mosmsg=Submission+received+with+ID+17747368

基本上的想法是 樹套樹 啦。

簡單來講,在一棵正常的segment tree(維護x軸 的 min&max)中,在塞一棵segment tree(維護y軸的)。那有一個小細節要注意,在modify裡面中!

好累喔,不太想打XD

#include <iostream>
#include <stdio.h>
#include <utility>
using namespace std;

typedef pair<int,int> pii;
const int MAX_N = 503;
const int INF = 1e9+7;

int n;

pii operator+(const pii &p1,const pii &p2) {
 return make_pair(max(p1.first,p2.first),min(p1.second,p2.second));
}

struct Node2 {
 Node2* lc;
 Node2* rc;
 pii val;
 Node2() {
  lc=rc=NULL;
  val=make_pair(-INF,INF);
 }
 void pull() {
  val= lc->val + rc->val;
 }
};

Node2* Build2(int L,int R) {
 Node2* node = new Node2();
 if (L==R) return node;
 int mid=(L+R)>>1;
 node->lc=Build2(L,mid);
 node->rc=Build2(mid+1,R);
 return node;
}

struct Node {
 Node* lc;
 Node* rc;
 Node2* c;
 Node(int n) {
  lc=rc=NULL;
  c = Build2(1,n);
 }
};

Node* root;

Node* Build1(int L,int R,int n) {
 Node* node = new Node(n);
 if (L==R) return node;
 int mid=(L+R)>>1;
 node->lc=Build1(L,mid,n);
 node->rc=Build1(mid+1,R,n);
 return node;
}

pii query1(Node* node,int n,int L,int R,int l,int r,int qy1,int qy2);

void modify2(Node2* node,int L,int R,int pos,int val,int x1,int x2,int qx) {
// cout<<"in 2 : "<<L<<" ~ "<<R<<endl;
 if (L==R) {
  if (x1!=x2) {
   node->val = query1(root,n,1,n,x1,qx-1,pos,pos) + query1(root,n,1,n,qx+1,x2,pos,pos) + make_pair(val,val);
  }
  else if (x1==x2){
   node->val = make_pair(val,val);
  }
  return;
 }
 int mid=(L+R)>>1;
 if (pos<=mid) modify2(node->lc,L,mid,pos,val,x1,x2,qx);
 else modify2(node->rc,mid+1,R,pos,val,x1,x2,qx);
 node->pull();
 return;
}

void modify1(Node* node,int n,int L,int R,int qx,int qy,int val) {
 modify2(node->c,1,n,qy,val,L,R,qx);
 if (L==R) {
  return;
 }
 int mid=(L+R)>>1;
 if (qx<=mid) modify1(node->lc,n,L,mid,qx,qy,val);
 else modify1(node->rc,n,mid+1,R,qx,qy,val);
 return;
}

pii query2(Node2* node,int L,int R,int l,int r) {
// cout<<"in 2 : "<<L<<" ~ "<<R<<endl; 
 if (L>r || l>R) return make_pair(-INF,INF);
 else if (l<=L && R<=r) return node->val;
 int mid=(L+R)>>1;
 return query2(node->lc,L,mid,l,r) + query2(node->rc,mid+1,R,l,r);
}

pii query1(Node* node,int n,int L,int R,int l,int r,int qy1,int qy2) {
// cout<<"in 1 : "<<L<<" ~ "<<R<<endl; 
 if (l>R || L>r) return make_pair(-INF,INF);
 else if (l<=L && R<=r) return query2(node->c,1,n,qy1,qy2);
 int mid=(L+R)>>1;
 return query1(node->lc,n,L,mid,l,r,qy1,qy2) + query1(node->rc,n,mid+1,R,l,r,qy1,qy2);
}

int main () {
// freopen("output.txt","w",stdout);
 while (scanf("%d",&n) != EOF) {
  root=Build1(1,n,n);
  for (int x=1;n>=x;x++) {
   for (int y=1;n>=y;y++) {
    int i;
    scanf("%d",&i);
    modify1(root,n,1,n,x,y,i);
//    cout<<"get = "<<query1(root,n,1,n,x,x,y,y).first<<' '<<query1(root,n,1,n,x,x,y,y).second<<endl;;
   }
  }
  int m;
  scanf("%d",&m);
  while (m--) {
   getchar();
   char i;
   scanf("%c",&i);
   if (i=='q') {
    int a,b,c,d;
    scanf("%d %d %d %d",&a,&b,&c,&d);
    pii ret=query1(root,n,1,n,a,c,b,d);
    printf("%d %d\n",ret.first,ret.second);
   }
   else if (i=='c') {
    int a,b,c;
    scanf("%d %d %d",&a,&b,&c);
    modify1(root,n,1,n,a,b,c);
   }
  }
 }
}

/*
5
1 2 3 4 5
0 9 2 1 3
0 2 3 4 1
0 1 2 4 5
8 5 3 1 4
4
q 1 1 2 3
c 2 3 10
q 1 1 5 5
q 1 2 2 2

10
98 14 55 72 2 15 19 54 32 58
60 35 46 96 44 70 3 76 58 11
34 65 48 45 49 17 74 51 25 68
82 76 34 37 0 37 4 19 43 37
29 3 72 75 0 68 45 55 44 56
18 31 73 18 28 74 36 2 25 13
22 60 41 57 49 41 46 54 13 89
43 42 92 67 70 44 88 67 52 32
75 70 63 0 41 91 74 77 45 0
42 20 12 84 77 61 77 75 67 90
50
c 6 3 8
c 6 8 18
c 3 8 2
q 3 7 8 7
q 6 10 8 10
q 9 2 9 2
q 3 10 10 10
c 4 4 66
c 5 9 66
q 1 10 6 10
q 5 10 8 10
q 4 4 10 9
q 1 3 2 3
c 7 7 39
q 6 3 8 4
c 1 1 81
c 9 10 35
c 10 3 1
c 5 3 74
c 8 8 83
c 8 9 4
*/

2016年7月27日 星期三

(UVA) 11284 - Shopping Trip

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=24&problem=2259&mosmsg=Submission+received+with+ID+17741643

基本的想法:位元dp

複雜度:O(2^p * p^2)

先用spfa求最短路徑(注意會有1-->0 cost 1.9, 0-->1 cost 3 的情況)

基本的想法是說:紀錄每個狀態 & 每個狀態最後是誰,最後在走訪一下即可。


#include <iostream>
#include <stdio.h>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;

const int MAX_N = 53;
const int MAX_M = 1003;
const int MAX_P = 14;
const int INF = 1e9+7;

int w[MAX_N][MAX_N];
vector<int> edg[MAX_N];
int d[MAX_N][MAX_N];
int dp[1<<MAX_P][MAX_P];
int cost[MAX_N];
bool in_que[MAX_N];
int store[MAX_P];

void init() {
 for (int x=0;MAX_N>x;x++) {
  for (int y=0;MAX_N>y;y++) {
   w[x][y] = d[x][y] = INF;
  }
  edg[x].clear();
  cost[x]=0;
 }
 for (int x=0;x < (1<<MAX_P);x++) {
  for (int y=0;MAX_P>y;y++) {
   dp[x][y] = INF;
   if (x==0) dp[x][y] = 0;
  }
 }
 memset(store,0,sizeof(store));
}

void spfa(int id) {
 d[id][id]=0;
 for (int x=0;MAX_N>x;x++) in_que[x]=false;
 queue<int> que;
 que.push(id);
 while (!que.empty()) {
  int t=que.front();
  que.pop();
  in_que[t]=false;
  for (auto i=edg[t].begin();i!=edg[t].end();i++) {
   int tmp = *i;
   if (d[id][tmp] > d[id][t] + w[t][tmp]) {
    d[id][tmp] = d[id][t] + w[t][tmp];
    if (in_que[tmp]==false) {
     que.push(tmp);
     in_que[tmp]=true;
    }
   }
  }
 }
}

int main () {
// freopen("output.txt","w",stdout);
 int T;
 scanf("%d",&T);
 while (T--) {
  init();
  int n,m;
  scanf("%d %d",&n,&m);
  for (int x=0;m>x;x++) {
   int i,j;
   int k,l;
   scanf("%d %d %d.%d",&i,&j,&k,&l);
   w[i][j] = min(w[i][j],k*100+l);
   w[j][i] = min(w[j][i],k*100+l);
   edg[i].push_back(j);
   edg[j].push_back(i);
  }
  int p;
  scanf("%d",&p);
  for (int x=0;p>x;x++) {
   int i;
   int j,k;
   scanf("%d %d.%d",&i,&j,&k);
   store[x]=i;
   cost[x]=j*100+k;
  }
  for (int x=0;n>=x;x++) spfa(x);
  for (int x=0;(1<<(p)) > x;x++) {
   for (int y=0;p>y;y++) {
    if ((x | (1<<y)) == x) {
     int tmp= (x ^ (1<<y));
     if (tmp==0) dp[x][y] = d[0][store[y]];
     else {
      for (int z=0;p>z;z++) {
       dp[x][y] = min(dp[x][y],dp[tmp][z] + d[store[z]][store[y]]);
      }
     }
    }
   }
  }
  int best = 0;
  for (int x=0;(1<<(p)) > x;x++) {
   for (int y=0;p>y;y++) {
//    cout<<"dp["<<x<<"]["<<y<<"] = "<<dp[x][y]<<endl;
    int tmp=0;
    //last = y
    for (int z=0;p>z;z++) {
     if (((1<<z) | x) == x) {
      tmp += cost[z];
     }
    }
//    cout << "x="<<x<<" , y="<<y<<" , tmp="<<tmp<<" , ";
//    cout<<"minus = "<<(dp[x][y] + d[store[y]][0])<<endl;
    tmp -= (dp[x][y] + d[store[y]][0]);
    
    best = max(best,tmp);
   }
  }
  if (best==0.0) puts("Don\'t leave the house");
  else printf("Daniel can save $%d.%02d\n",best/100,best%100);
 }
}


2016年7月22日 星期五

(UVA) 11790 - Murcia's Skyline [max value of increasing sequence]

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=&problem=2890&mosmsg=Submission+received+with+ID+17713804

可以把題目簡化成這個樣子:

給你兩個長度n的序列(題目沒給n的大小QQ,看了我的作法後,我覺得n可以到1e5量級),第一個序列叫 a, 第二個序列就b。

每當從a序列選擇一個元素ai時,可以獲得bi的價值。

那我就假設a序列叫 "重量" , b序列叫 "價值"

現在,請你找到一條嚴格遞增 & 嚴格遞減 序列,使得這兩個的價值分別最大,最後按照比較輸出。

我的想法是這樣:開一個segment tree維護最小值,令segment tree的位置 i 的意義為:以重量i為尾巴的 遞增(遞減) 序列,最大的 "價值" 是多少。

對於每個新來的重量w,價值v,我先找 (1~w-1)的 max,加了v之後,存到線段樹 w的位置。

複雜度:O (n lg n)

(我也有在code離散化了一下)


#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>
using namespace std;

const int MAX_N = 1e5+6;
int w[MAX_N];
int v[MAX_N];

struct Node {
 Node *lc,*rc;
 int val;
 Node() {
  lc=rc=NULL;
  val=0;
 }
 void pull() {
  val=max(lc->val, rc->val);
 }
};

Node* Build(int L,int R) {
 Node* node = new Node();
 if (L==R) {
  return node;
 }
 int mid=(L+R)>>1;
 node->lc=Build(L,mid);
 node->rc=Build(mid+1,R);
 return node;
}

void modify(Node* node,int L,int R,int pos,int val) {
 if (L==R) {
  if (val > node->val) node->val = val;
  return;
 }
 int mid=(L+R)>>1;
 if (pos<=mid) modify(node->lc,L,mid,pos,val);
 else modify(node->rc,mid+1,R,pos,val);
 node->pull();
 return;
}

int query(Node* node,int L,int R,int l,int r) {
 if (l>R || L>r) return 0;
 else if(l<=L && R<=r) return node->val;
 int mid=(L+R)>>1;
 return max(query(node->lc,L,mid,l,r),query(node->rc,mid+1,R,l,r));
}

vector<int> vec;

int main () {
// freopen("output.txt","w",stdout);
 int T;
 scanf("%d",&T);
 for (int qq=1;T>=qq;qq++) {
  printf("Case %d. ",qq);
  vec.clear();
  int n;
  scanf("%d",&n);
  for (int x=1;n>=x;x++) {
   scanf("%d",&w[x]);
   vec.push_back(w[x]);
  }
  for (int x=1;n>=x;x++) {
   scanf("%d",&v[x]);
  }
  sort(vec.begin(),vec.end());
  vec.resize(unique(vec.begin(),vec.end()) - vec.begin());
  for (int x=1;n>=x;x++) {
   w[x] = lower_bound(vec.begin(),vec.end(),w[x]) - vec.begin() + 1;
  }
  Node* root=Build(1,n);
  for (int x=1;n>=x;x++) {
   modify(root,1,n,w[x],query(root,1,n,1,w[x]-1)+v[x]);
  }
  int A=query(root,1,n,1,n);
  
  for(int x=1;n>=x;x++) w[x] = n - w[x] + 1;
  root=Build(1,n);
  
  for (int x=1;n>=x;x++) {
   modify(root,1,n,w[x],query(root,1,n,1,w[x]-1)+v[x]);
  }
  int B=query(root,1,n,1,n);
  
  if (A>=B) printf("Increasing (%d). Decreasing (%d).\n",A,B);
  else printf("Decreasing (%d). Increasing (%d).\n",B,A);
 }
}


2016年7月21日 星期四

(UVA) 11517 - Exact Change

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=24&problem=2512&mosmsg=Submission+received+with+ID+17707369

dp一番即可

O(n * 10000)


#include <iostream>
#include <stdio.h>
#include <utility>
using namespace std;

typedef pair<int,int> pii;
const int MAX_N = 103;
const int MAX_V = 10003;

pii dp[MAX_N][2*MAX_V];
int w[MAX_N],v[MAX_N];

pii operator+(const pii &p1,const pii &p2) {
 return make_pair(p1.first+p2.first,p1.second+p2.second);
}

int main () {
 int T;
 scanf("%d",&T);
 while (T--) {
  int p;
  scanf("%d",&p);
  int n;
  scanf("%d",&n);
  for (int x=1;n>=x;x++) {
   scanf("%d",&w[x]);
   v[x]=w[x];
  }
  for (int x=1;n>=x;x++) {
   for (int y=1;2*MAX_V>y;y++) {
    dp[x][y]=make_pair(0,0);
   }
  }
  for (int i=1;n>=i;i++) {
   for (int j=1;2*MAX_V>j;j++) {
    if (j-w[i] < 0) dp[i][j]=dp[i-1][j];
    else dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+make_pair(v[i],-1));
   }
  }
  pii ans=dp[n][p];
  if (ans.first==p) {
   printf("%d %d\n",ans.first,-ans.second);
  }
  else {
   int id=p+1;
   while (1) {
    if (dp[n][id].first>=p) {
     ans=dp[n][id];
     printf("%d %d\n",ans.first,-ans.second);
     break;
    }
    id++;
   }
  }
 }
}


(UVA) 11951 - Area

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=24&problem=3102&mosmsg=Submission+received+with+ID+17707156

沒想到這題 O(n^3 lg n)可以過~~ (搞不好n^4也可以過XD)

基本想法是:枚舉x1,x2,y1,利用二分搜找y2


#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;

typedef long long LL;
const int MAX_N = 102;

LL sum[MAX_N][MAX_N];
LL row[MAX_N][MAX_N]; //a[1~x][1~y]
LL col[MAX_N][MAX_N];

int main () {
 int T;
 scanf("%d",&T);
 for (int qq=1;T>=qq;qq++) {
  printf("Case #%d: ",qq);
  memset(sum,0,sizeof(sum));
  LL n,m,k;
  scanf("%lld %lld %lld",&n,&m,&k);
  for (int x=1;n>=x;x++) {
   for (int y=1;m>=y;y++) {
    int p;
    scanf("%d",&p);
    sum[x][y] = sum[x-1][y] + sum[x][y-1] - sum[x-1][y-1] + p;
   }
  }
//  for (int x=1;n>=x;x++) {
//   for (int y=1;n>=y;y++) {
//    cout<<sum[x][y]<< ' ';
//   }
//   cout<<endl;
//  }
  LL ans1=0,ans2=0;
  for (int x1=1;n>=x1;x1++) {
   for (int y1=1;m>=y1;y1++) {
    for (int x2=x1;n>=x2;x2++) {
     //binary got y2
     int L=y1-1,R=m+1;
     while (R-L!=1) {
      int mid=(L+R)>>1;
      LL t=sum[x2][mid] + sum[x1-1][y1-1] - sum[x2][y1-1] - sum[x1-1][mid];
      if (t<=k) {
       L=mid;
      }
      else {
       R=mid;
      }
     }
     LL t=sum[x2][L] + sum[x1-1][y1-1] - sum[x2][y1-1] - sum[x1-1][L];
     if (t<=k) {
      if ((x2-x1+1) * (L-y1+1) > ans1) {
       ans1=(x2-x1+1) * (L-y1+1);
       ans2=t;
      }
      else if ((x2-x1+1) * (L-y1+1) == ans1 && t<ans2) ans2=t;
     }
    }
   }
  }
  printf("%lld %lld\n",ans1,ans2);
 }
}


2016年7月20日 星期三

Codeforces Round #363 (Div. 2)

http://codeforces.com/contest/699

題目:
pA : http://codeforces.com/contest/699/problem/A
pB : http://codeforces.com/contest/699/problem/B
pC : http://codeforces.com/contest/699/problem/C
pD : http://codeforces.com/contest/699/problem/D
pE : http://codeforces.com/contest/699/problem/E
pF : http://codeforces.com/contest/699/problem/F

我AC的code :
pA : http://codeforces.com/contest/699/submission/19263590
pB : http://codeforces.com/contest/699/submission/19235904
pC : http://codeforces.com/contest/699/submission/19239284
pD : http://codeforces.com/contest/699/submission/19250329

詳解:

pA :
枚舉每個點,如果這個點是L和下個點是R,更新答案。O(n)

pB :
記錄每行每列有多少個*,枚舉所有的點(x,y)檢查,如果row[x] + col[y] = sum,那就okay

pC :
開三條dp陣列,紀律最後一天是rest, gym, contest所需要rest的min。更新的方法是rest-->rest,gym,contest ; gym-->rest,contest, contest-->gym,rest

pD :
這題頗精彩XD
看code自己想XD

好啦,就是
想辦法把圖中的任意邊連到根,詳細作法可以參考MST的Kruskal做法(我是這樣套用啦)





2016年7月9日 星期六

a066: HNOI2002 营业额统计

http://cat.nknush.kh.edu.tw/ShowProblem?problemid=a066

如果題目少輸入的話,用0去算!!!(害我debug了大約20min!!!)

很重要!!!

我放的code是如果測資是okay的code,直接貼上去是會吃NA(score : 80)的喔!

想法:開一個treap維護數字XDDD,數值線段樹也應該可以,不過最近發現treap比較好co ^_^


#include <iostream>
#include <stdio.h>
#include <ctime>
#include <cstdlib>
#include <cmath>
using namespace std;

struct Treap {
 Treap* lc;
 Treap* rc;
 int pri;
 int key;
 int mn,mx;
 Treap(int _key) {
  lc=rc=NULL;
  mn=mx=key=_key;
  pri=rand();
 }
};

const int INF = 1e9+7;

int Mx(Treap* t) {
 return t?t->mx:-INF;
}

int Mn(Treap* t) {
 return t?t->mn:INF;
}

void pull(Treap* t) {
 t->mx = max(Mx(t->lc),Mx(t->rc));
 t->mx = max(t->mx,t->key);
 t->mn = min(Mn(t->lc),Mn(t->rc));
 t->mn = min(t->mn,t->key);
}

Treap* merge(Treap* a,Treap* b) {
 if (!a || !b) return a?a:b;
 else if (a->pri > b->pri) {
  a->rc = merge(a->rc,b);
  pull(a);
  return a;
 }
 else {
  b->lc = merge(a,b->lc);
  pull(b);
  return b;
 }
}

void split(Treap* t,int k,Treap* &a,Treap* &b) {
 if (!t) a=b=NULL;
 else if (t->key <= k) {
  a=t;
  split(t->rc,k,a->rc,b);
  pull(a);
 }
 else {
  b=t;
  split(t->lc,k,a,b->lc);
  pull(b);
 }
}

int main () {
 srand(time(NULL));
 int n;
 while (scanf("%d",&n) != EOF) {
  Treap* root=NULL;
  long long int sum=0;
  for (int x=0;n>x;x++) {
   int i;
   scanf("%d",&i);
   if (x==0) {
    sum+=i;
    root = merge(root,new Treap(i));
   }
   else {
    Treap* tl;
    Treap* tr;
    split(root,i-1,tl,root);
    split(root,i,root,tr);
    if (tl) pull(tl);
    if (tr) pull(tr);
    int MX=Mx(tl);
    int MN=Mn(tr);
//    cout<<"mx = "<<MX<<" , mn = "<<MN<<endl;
    if (!root) sum+=min(abs(i-MX),abs(i-MN));
    root = merge(root,new Treap(i));
    root = merge(merge(tl,root),tr);
   }
  }
  printf("%lld\n",sum);
 }
}