• 北京集训: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
    其实就是如月红啦......
    准备把北京集训系列都改成这个密码的说......
    (不要用"这个死肥宅又换老婆了"的眼神看着这里嘛)

  • 相关阅读:
    [剑指offer] 7. 斐波那契数列
    [剑指offer] 6. 旋转数组的最小数字
    [剑指offer] 5. 用两个栈实现队列
    [剑指offer] 4. 重建二叉树
    [剑指offer] 3. 从头到尾打印链表
    vue.js从输入中的contenteditable元素获取innerhtml
    CSS3 ------- object-fit属性
    mouseenter和mouseover区别
    元素scroll系列属性
    淘宝flexible.js源码分析
  • 原文地址:https://www.cnblogs.com/Cmd2001/p/8621455.html
Copyright © 2020-2023  润新知