• 北京集训:20180321


    动态题目问题,我们需要自动AC机......

    T1:


    看到划掉的那部分了吗,没错,考试中途改题面了......
    然而我只会写15分爆搜......
    计算几何+构造,不改了,爆搜滚粗了......
    以下为官方题解:


    15分爆搜代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<cstdlib>
     7 #define debug cout
     8 typedef long long int lli;
     9 using namespace std;
    10 const int maxn=1e4+1e1;
    11 const double pi = acos(-1.0);
    12 
    13 struct Point {
    14     lli x,y;
    15     inline friend Point operator - (const Point &a,const Point &b) {
    16         return (Point){a.x-b.x,a.y-b.y};
    17     }
    18     inline friend lli operator * (const Point &a,const Point &b) {
    19         return a.x * b.y - a.y * b.x;
    20     }
    21     inline double dis() const {
    22         return sqrt(x*x+y*y);
    23     }
    24     friend bool operator < (const Point &a,const Point &b) {
    25         return a.x < b.x;
    26     }
    27 }ps[maxn];
    28 int a[maxn],b[maxn],cnt;
    29 bool used[maxn];
    30 long double sum;
    31 int n;
    32 
    33 inline bool iscorss(const Point &pa,const Point &pb,const Point &ta,const Point &tb) {
    34     if( min(ta.x,tb.x) > max(pa.x,pb.x)
    35      || min(pa.x,pb.x) > max(ta.x,tb.x)
    36      || min(ta.y,tb.y) > max(pa.y,pb.y)
    37      || min(pa.y,pb.y) > max(ta.y,tb.y) )
    38         return 0;
    39     return ( (__int128)((tb-pa)*(pb-pa)) * ((pb-pa)*(ta-pa)) > 0 && (__int128)((tb-pb)*(pa-pb)) * ((pa-pb)*(ta-pb)) > 0 );
    40 }
    41 inline bool judge(const int &nx,const int &ny) {
    42     for(int i=1;i<=cnt;i++) {
    43         if( iscorss(ps[a[i]],ps[b[i]],ps[nx],ps[ny]) ) return 0;
    44     }
    45     return 1;
    46 }
    47 inline bool checkans() {
    48     double ret = 0;
    49     for(int i=1;i<=cnt;i++) ret += ( ps[a[i]] - ps[b[i]] ).dis();
    50     return ret * pi >= sum * 2.0;
    51 }
    52 inline void finish() {
    53     if( !checkans() ) return;
    54     for(int i=1;i<=cnt;i++) printf("%d %d
    ",a[i],b[i]);
    55     exit(0);
    56 }
    57 inline void dfs(int pos) {
    58     if( pos > n << 1 ) return finish();
    59     if( used[pos] ) return dfs(pos+1);
    60     used[pos] = 1;
    61     for(int i=pos+1;i<=n<<1;i++) if( !used[i] && judge(pos,i) ) {
    62         used[i] = 1 , a[++cnt] = pos , b[cnt] = i;
    63         dfs(pos+1);
    64         used[i] = 0 , --cnt;
    65     }
    66     used[pos] = 0;
    67 }
    68 
    69 int main() {
    70     scanf("%d",&n);
    71     if( n > 15 ) return 0;
    72     for(int i=1;i<=n<<1;i++) scanf("%lld%lld",&ps[i].x,&ps[i].y);
    73     for(int i=1,a,b;i<=n;i++) {
    74         scanf("%d%d",&a,&b) ,
    75         sum += ( ps[a] - ps[b] ).dis();
    76     }
    77     dfs(1);
    78     return 0;
    79 }
    View Code

    标程代码:

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3  
      4 #define db int
      5 #define eps 0
      6 struct point{db x,y;};
      7 point operator +(point a,point b){return (point){a.x+b.x,a.y+b.y};}
      8 point operator -(point a,point b){return (point){a.x-b.x,a.y-b.y};}
      9 bool operator < (const point &a,const point &b){return a.x==b.x? a.y<b.y:a.x<b.x;}
     10 long long operator *(point a,point b){return a.x*1LL*b.y-b.x*1LL*a.y;}
     11 db sg(long long x){return (x>-eps) - (x<eps);}
     12 db sideofb(point a,point b){return sg(a*b);}//-1 left
     13 bool a_onleft(point a,point b){return a*b<-eps;}
     14 long double dis(point a,point b){
     15     return sqrt((a.x-b.x)*1LL*(a.x-b.x)+(a.y-b.y)*1LL*(a.y-b.y));
     16 }
     17 #undef db
     18 #undef eps
     19 #define eps 1e-10
     20 #define N 10005
     21 point p[N];
     22 int n,mat[N],col[N];
     23 double theta[N],cval[N],sval[N];
     24 double d[N];
     25 const double pi=acos(-1);
     26 double reg(double ang){
     27     while(ang<0) ang+=pi;
     28     while(ang>pi) ang-=pi;
     29     return ang;
     30 }
     31 double tot=0,limit=2/pi;
     32 double getans(double ang){
     33     long double a0=0,a1=0;//a0cosx - a1cosx
     34     for(int i=1;i<=n;i++){
     35         if(i>mat[i]) continue;
     36         if(cos(theta[i]-ang)<0) a0-=cval[i],a1-=sval[i];
     37         else a0+=cval[i],a1+=sval[i];
     38     }
     39     long double ret=atan(a1/a0),mL=0;
     40     if(a0<eps&&a0>-eps) ret=pi/2;
     41     mL=a0*cos(ret)+a1*sin(ret);
     42     if(mL<0)
     43         mL=-mL,ret=ret+pi;
     44     if(mL>=limit*tot) return reg(ret);
     45     else return -1;
     46 }
     47 double findBestAngle(){
     48     vector<double> div;tot=0;
     49     for(int i=1;i<=n;i++)
     50         if(mat[i]>i){
     51             point t=p[mat[i]]-p[i];
     52             theta[i]=atan2(t.y,t.x);
     53             div.push_back(reg(theta[i]-pi/2));
     54             tot+= (d[i]=dis(p[mat[i]],p[i]));
     55             cval[i]=cos(theta[i])*d[i];
     56             sval[i]=sin(theta[i])*d[i];
     57         }
     58     div.push_back(0);div.push_back(pi);
     59     sort(div.begin(),div.end());
     60      
     61     double ret=-1;
     62     for(int i=1;i<div.size();i++){
     63         if(div[i]-div[i-1]>1e-8){
     64             ret=getans((div[i]+div[i-1])/2);
     65             if(ret>=0) return ret;
     66         }
     67     }
     68     assert(false);
     69 }
     70  
     71 int arr[N],base;
     72 bool cmp(int a,int b){
     73     return sideofb(p[a]-p[base],p[b]-p[base])<0;
     74 }
     75 void solve(int l,int r){
     76     int mn=l;
     77     for(int i=l+1;i<=r;i++)
     78         if(p[arr[i]]<p[arr[mn]]) mn=i;
     79     swap(arr[mn],arr[l]);base=arr[l];
     80     sort(arr+l+1,arr+r+1,cmp);
     81     int best=l-1;
     82     for(int i=l+1,pre=col[arr[l]];i<=r;i++){
     83         pre+=col[arr[i]];
     84         if(pre==0&&col[arr[i]]+col[arr[l]]==0)
     85             if(min(r-i,i-l)>min(r-best,best-l)) best=i;
     86     }
     87     mat[arr[l]]=arr[best],mat[arr[best]]=arr[l];
     88     if(best!=l+1) solve(l+1,best-1);
     89     if(best!=r) solve(best+1,r);
     90     return;
     91 }
     92  
     93 void readin(){
     94     scanf("%d",&n);n*=2;
     95     for(int i=1;i<=n;i++)
     96         scanf("%d%d",&p[i].x,&p[i].y);
     97     for(int i=1,f,t;i<=n/2;i++)
     98         scanf("%d%d",&f,&t),mat[f]=t,mat[t]=f;
     99 }
    100  
    101 void solve() {
    102     double ang=findBestAngle(),px=cos(ang),py=sin(ang);
    103     vector<pair<double,int> > fl; 
    104     for(int i=1;i<=n;i++)
    105         fl.push_back(make_pair(px*p[i].x+py*p[i].y,i));
    106     sort(fl.begin(),fl.end() );
    107     for(int i=0;i<n;i++)
    108         col[fl[i].second]=(i<n/2? 1:-1);
    109      
    110     for(int i=1;i<=n;i++) arr[i]=i;
    111     solve(1,n);
    112      
    113     for(int i=1;i<=n;i++)
    114         if(i<mat[i])
    115             printf("%d %d
    ",i,mat[i]);
    116 }
    117  
    118 int main(){
    119     readin();
    120     solve();
    121     return 0;
    122 }
    View Code


    T2:


    5分边权求和乘2,10分代价减去直径......
    好了,反正是欢乐赛,可以滚粗了。
    考虑55分怎么写,我们只需要一个O(nk)的算法
    像堆贪心一样每次把选择的路径的价值取反,然后重新找最长链并选择,中间重合的部分选择了两次相当于没选。
    我们这样做最多k次就能得出方案。
    最长链必须用树状DP求,两遍dfs的方法依赖了距离的单调性,很容易构造反例。
    同时不能让second默认-1,因为可能有强行更新的情况。(其实我们用max和每个子树去更新就好了)
    然后,这样想就想不出正解了......
    考虑如果我们知道一个坐车的价值,如何计算出遍历整棵树最小代价和需要的坐车次数?
    树状DP,f[i][0/1]表示遍历i的子树,最终回到i的时候是否坐车,需要的最小价值和坐车次数(记录二元组)。
    枚举四种遍历方式进行转移。
    如果计算出的坐车次数比k大怎么办?
    我们提高坐车代价,显然次数是单调的,然后我们找到坐车次数恰好小于等于k的那个点。
    这个点所代表的值,就是每次坐车能替换的最大代价。
    然后我们用dp出的代价减去k*差值即可(我的代码里仅计算单程代价,因为每条边必须走路经过一遍,可以提前求和)。
    明明前几天刚做过思路相同的题目的,为什么不会?
    http://www.lydsy.com/JudgeOnline/problem.php?id=2654
    考场10分代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 
     7 int n,k,c;
     8 
     9 namespace Case1 {
    10     inline void work() {
    11         int sum = 0;
    12         for(int i=1,w;i<n;i++) scanf("%*d%*d%d",&w) , sum += w;
    13         printf("%d
    ",sum<<1);
    14     }
    15 }
    16 namespace Case2 {
    17     const int maxn=2e2+1e1;
    18     int s[maxn],t[maxn<<1],nxt[maxn<<1],l[maxn<<1],dep[maxn],cnt,mxp;
    19     inline void addedge(int from,int to,int len) {
    20         t[++cnt] = to , l[cnt] = len ,
    21         nxt[cnt] = s[from] , s[from] = cnt;
    22     }
    23     inline void dfs(int pos,int fa) {
    24         if( dep[pos] > dep[mxp] ) mxp = pos;
    25         for(int at=s[pos];at;at=nxt[at]) if( t[at] != fa ) {
    26             dep[t[at]] = dep[pos] + l[at] , dfs(t[at],pos);
    27         }
    28     }
    29     inline void work() {
    30         int sum = 0;
    31         memset(s,0,sizeof(s)) , cnt = 0;
    32         for(int i=1,a,b,l;i<n;i++) {
    33             scanf("%d%d%d",&a,&b,&l) , sum += l , ++a , ++b;
    34             addedge(a,b,l) , addedge(b,a,l);
    35         }
    36         dep[mxp=1] = 0  , dfs(1,-1);
    37         dep[mxp] = 0 , dfs(mxp,-1);
    38         ( sum <<= 1 ) -= max( dep[mxp] - c , 0 );
    39         printf("%d
    ",sum);
    40     }
    41 }
    42 
    43 int main() {
    44     while( scanf("%d%d%d",&n,&k,&c) == 3 ) {
    45         if( k == 0 ) Case1::work();
    46         else if( k == 1 ) Case2::work();
    47     }
    48     return 0;
    49 }
    View Code

    55分暴力代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring> 
     4 #include<algorithm>
     5 #define debug cout
     6 using namespace std;
     7 const int maxn=2e3+1e2;
     8 const int inf=0x3f3f3f3f;
     9 
    10 int s[maxn],t[maxn<<1],nxt[maxn<<1],l[maxn<<1],cnt;
    11 int fa[maxn],dep[maxn],sou[maxn],dis[maxn],mxd[maxn],scd[maxn];
    12 int pa,pb,pdis;
    13 
    14 inline void coredge(int from,int to,int len) {
    15     t[++cnt] = to , l[cnt] = len , 
    16     nxt[cnt] = s[from] , s[from] = cnt;
    17 }
    18 inline void doubledge(int from,int to,int len) {
    19     coredge(from,to,len) , coredge(to,from,len);
    20 }
    21 
    22 inline void pre(int pos) {
    23     for(int at=s[pos];at;at=nxt[at]) if( t[at] != fa[pos] ) {
    24         fa[t[at]] = pos , sou[t[at]] = at ,
    25         dep[t[at]] = dep[pos] + 1 , pre(t[at]);
    26     }
    27 }
    28 inline void dfs(int pos) {
    29     mxd[pos] = pos , scd[pos] = pos , dis[pos] = 0;
    30     for(int at=s[pos];at;at=nxt[at]) if( t[at] != fa[pos] ) {
    31         dfs(t[at]) , dis[mxd[t[at]]] += l[at];
    32         if( dis[mxd[t[at]]] >= dis[mxd[pos]] ) scd[pos] = mxd[pos] , mxd[pos] = mxd[t[at]];
    33         else if( dis[mxd[t[at]]] > dis[scd[pos]] ) scd[pos] = mxd[t[at]];
    34     }
    35     if( dis[mxd[pos]] + dis[scd[pos]] > pdis ) {
    36         pa = mxd[pos] , pb = scd[pos] , pdis = dis[mxd[pos]] + dis[scd[pos]];
    37     }
    38 }
    39 inline void reval(int a,int b) {
    40     while( a != b ) {
    41         if( dep[a] > dep[b] ) l[sou[a]] = l[sou[a]^1] = -l[sou[a]] , a = fa[a];
    42         else l[sou[b]] = l[sou[b]^1] = -l[sou[b]] , b = fa[b];
    43     }
    44 }
    45 
    46 inline void reset(int n) {
    47     memset(s,0,sizeof(*s)*(n+1)) , cnt = 1;
    48 }
    49 
    50 int main() {
    51     static int n,k,c,sum;
    52     while( scanf("%d%d%d",&n,&k,&c) == 3 ) {
    53         reset(n) , sum = 0;
    54         for(int i=1,a,b,l;i<n;i++) {
    55             scanf("%d%d%d",&a,&b,&l) , sum += l << 1;
    56             doubledge(++a,++b,l);
    57         }
    58         pre(1);
    59         while( k ) {
    60             pa = pb = -1 , pdis = -inf;
    61             dfs(1);
    62             if( pdis >= c ) sum -= pdis - c  , --k , reval(pa,pb);
    63             else break;
    64         }
    65         printf("%d
    ",sum);
    66     }
    67     return 0;
    68 }
    View Code

    正解代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define debug cout
     6 using namespace std;
     7 const int maxn=2e4+1e2;
     8 
     9 struct Node {
    10     int val,siz;
    11     friend Node operator + (const Node &a,const Node &b) {
    12         return (Node){a.val+b.val,a.siz+b.siz};
    13     }
    14     friend Node operator - (const Node &a,const Node &b) {
    15         return (Node){a.val-b.val,a.siz-b.siz};
    16     }
    17     friend bool operator < (const Node &a,const Node &b) {
    18         return a.val != b.val ? a.val < b.val : a.siz < b.siz;
    19     }
    20 }f[maxn][2],per;
    21 
    22 int s[maxn],t[maxn<<1],nxt[maxn<<1],l[maxn<<1],cnt;
    23 int n,k,c,sum;
    24 
    25 inline void addedge(int from,int to,int len) {
    26     t[++cnt] = to , l[cnt] = len ,
    27     nxt[cnt] = s[from] , s[from] = cnt;
    28 }
    29 
    30 inline void dfs(int pos,int fa) {
    31     f[pos][0] = (Node){0,0} , f[pos][1] = per; // only access point pos by car .
    32     for(int at=s[pos];at;at=nxt[at]) if( t[at] != fa ) {
    33         dfs(t[at],pos);
    34         const Node w = (Node){l[at],0};
    35         const Node tp0 = std::min( f[pos][1] + f[t[at]][1] - per , f[pos][0] + f[t[at]][0] + w );
    36         // access t[at] and other sons by car and walk back , access t[at] and other sons on foot and walk back .
    37         const Node tp1 = std::min( f[pos][1] + f[t[at]][0] + w , f[pos][0] + f[t[at]][1] );
    38         // access other t[at] on foot first and access other sons by car , access other sons on foot first and access t[at] by car .
    39         f[pos][0] = std::min( tp0 , tp1 ) , f[pos][1] = std::min( tp0 + per , tp1 );
    40     }
    41 }
    42 
    43 inline Node calc(int cost) {
    44     per = (Node){cost,1};
    45     dfs(1,-1);
    46     return f[1][0];
    47 }
    48 inline void bin() {
    49     Node now;
    50     if( ( now = calc(c) ).siz <= k ) return void(printf("%d
    ",sum+now.val));
    51     int ll = 0 , rr = 1e9 , mid;
    52     while( rr > ll + 1 ) {
    53         mid = ( ll + rr ) >> 1;
    54         if( ( now = calc(mid) ).siz <= k ) rr = mid;
    55         else ll = mid;
    56     }
    57     now = calc(rr);
    58     printf("%d
    ",sum+now.val-k*(rr-c));
    59 }
    60 
    61 inline void init() {
    62     memset(s,0,sizeof(int)*(n+1)) , sum = cnt = 0;
    63 }
    64 
    65 int main() {
    66     while( scanf("%d%d%d",&n,&k,&c) == 3 ) {
    67         init();
    68         for(int i=1,a,b,l;i<n;i++) {
    69             scanf("%d%d%d",&a,&b,&l) , ++a , ++b , sum += l;
    70             addedge(a,b,l) , addedge(b,a,l);
    71         }
    72         bin();
    73     }
    74     return 0;
    75 }
    View Code


    T3:


    我说这题修改了5次数据你信吗......
    考场上看到这种情况根本不愿意写这题......
    首先说明题意:一个插线板会在某时间段开始的时候被插入,在某时间段结束的时候被移除。
    同时每个同学只能利用一个插线板,不能中途更换插线板。
    这个同学利用的 插线板起始点 一定<= l ,所以我们可以枚举这个 插线板的起始点 。
    考虑分块,我们可以预处理出 起始点小于等于每个块起点的某个时间 到 所有终点 的代价。
    然后暴力计算 起始点 从 块左 到 用电起始点l 的代价。
    对于第二个,我们可以主席树求和计算,而我orz了何中天大爷的可持久化块状数组写法。
    毕竟这个东西查询修改O(sqrt),查询O(1),而这个题显然查询更多一些。
    代码:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<set>
      6 #define debug cout
      7 using namespace std;
      8 const int maxn=1e5+1e2,blk=3e2;
      9 const int inf=0x3f3f3f3f;
     10 
     11 struct PersistentBlockedArray {
     12     int* p[maxn/blk+2];
     13     inline void update(int x) {
     14         const int bel = x / blk;
     15         int* t = new int[blk];
     16         if( p[bel] ) memcpy(t,p[bel],sizeof(int)*blk);
     17         else memset(t,0,sizeof(int)*blk);
     18         ++t[x%blk] , p[bel] = t;
     19     }
     20     inline int query(int x) {
     21         const int bel = x / blk;
     22         return p[bel] ? p[bel][x%blk] : 0;
     23     }
     24 }arr[maxn];
     25 
     26 struct Event {
     27     int tpe,tim,id;
     28     friend bool operator < (const Event &a,const Event &b) {
     29         return a.tim < b.tim;
     30     }
     31 }eve[maxn];
     32 int l[maxn],r[maxn],suc[maxn];
     33 int sum[maxn],pans[maxn/blk+2][maxn];
     34 int n,m,cnt;
     35 
     36 inline void getsuc() {
     37     set<int> s;
     38     for(int i=1;i<=n;i++) {
     39         if( !eve[i].tpe ) s.erase(eve[i].id);
     40         set<int>::iterator it = s.lower_bound(eve[i].id);
     41         if( it != s.end() ) suc[i] = *it;
     42         if( eve[i].tpe ) s.insert(eve[i].id);
     43     }
     44 }
     45 inline void prearr() {
     46     for(int i=1;i<=n;i++) {
     47         arr[i] = arr[i-1];
     48         if( !eve[i-1].tpe && suc[i-1] ) arr[i].update(suc[i-1]);
     49         if( eve[i].tpe && suc[i] ) arr[i].update(suc[i]);
     50     }
     51 }
     52 inline void getpans() {
     53     for(int j=1;j<=n;j+=blk) {
     54         memset(sum,0,sizeof(sum));
     55         for(int i=j;i<=n;i++) if( suc[i] ) ++sum[suc[i]];
     56         int miv = inf;
     57         for(int i=n;i>=j;i--) {
     58             const int id = eve[i].id , su = suc[i];
     59             if( !eve[i].tpe && l[id] <= j ) miv = min( miv , sum[id] );
     60             if( !eve[i].tpe && su ) {
     61                 --sum[su];
     62                 if( l[su] <= j ) miv = min( miv  , sum[su] );
     63             }
     64             pans[j/blk][i] = miv;
     65             if( eve[i].tpe && su ) {
     66                 --sum[su];
     67                 if( l[su] <= j ) miv = min( miv , sum[su] );
     68             }
     69         }
     70     }
     71 }
     72 
     73 inline int solve(int ll,int rr) {
     74     if( ll < 0 || rr > n || ll > rr ) cerr<<"illeagle argument !"<<endl,exit(0);
     75     const int bl = ( ll - 1 ) / blk;
     76     int ret = pans[bl][rr];
     77     for(int i=bl*blk+1;i<=ll;i++) {
     78         const int id = eve[i].id , su = suc[i];
     79         if( r[id] >= rr ) ret = min( ret , arr[rr].query(id) - arr[ll].query(id) );
     80         if( r[su] >= rr ) ret = min( ret , arr[rr].query(su) - arr[ll].query(su) );
     81     }
     82     return ret;
     83 }
     84 
     85 int main() {
     86     int lastans=0,tpe;
     87     scanf("%d%*d%d%d",&n,&m,&tpe);
     88     for(int i=1;i<=n;i++) {
     89         scanf("%d%d",l+i,r+i);
     90         eve[++cnt] = (Event){1,l[i],i} , eve[++cnt] = (Event){0,r[i],i};
     91     }
     92     sort(eve+1,eve+1+(n=cnt)) , n = cnt;
     93     getsuc() , prearr() ,
     94     getpans();
     95     for(int i=1,l,r;i<=m;i++) {
     96         scanf("%d%d",&l,&r);
     97         if( tpe ) l ^= lastans , r ^= lastans;
     98         lastans = solve(l,r);
     99         printf("%d
    ",lastans!=inf?lastans:-1);
    100         if( lastans == inf ) lastans = 0;
    101     }
    102     return 0;
    103 }
    View Code



    关于本文密码:
    KurenaiKisaragi
    其实就是如月红啦......
    准备把北京集训系列都改成这个密码的说......
    (不要用"这个死肥宅又换老婆了"的眼神看着这里嘛)

  • 相关阅读:
    Java异常处理和设计
    一次qps测试实践
    Alternate Task UVA
    Just Another Problem UVA
    Lattice Point or Not UVA
    Play with Floor and Ceil UVA
    Exploring Pyramids UVALive
    Cheerleaders UVA
    Triangle Counting UVA
    Square Numbers UVA
  • 原文地址:https://www.cnblogs.com/Cmd2001/p/8621455.html
Copyright © 2020-2023  润新知