20190807
咕了很长时间了QAQ
T1. 旋转子段
话说 n^2 思路也很棒....(对于想不到正解的我而言
枚举中心点 mid ,长度 len,由小长度向大长度双向扩展. 其实离正解差一个结论,就是你的 旋转边界 旋转过后 一定能对答案做 1 个贡献.(要不你完全可以将区间左右同时缩小 即由 [ i , j ] 变为 [ i + 1 , j - 1 ] .)所有优秀区间一定满足上述条件. 所以可以根据 mid 分类,对于每一个 mid 执行上述扩展操作,并更新答案. 复杂度的话,由于只有 n 个上述符合条件的边界,加上 sort 共是 nlogn.
1 #include <algorithm> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 #include <vector> 6 #include <cmath> 7 #include <queue> 8 #define QAQ 500010 9 #define re register 10 #define fup(i,a,b) for(re int i=a;i<=b;++i) 11 #define fdn(i,a,b) for(re int i=a;i>=b;--i) 12 #define mp(a,b) make_pair(a,b) 13 int n; 14 int sum[QAQ]; 15 using namespace std; 16 std::vector< pair<int,int> >wtf[QAQ<<1]; 17 inline int read() { 18 re int x(0),f(1);re char ch=getchar(); 19 while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } 20 while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); } 21 return x*f; 22 } 23 int main() { n=read(); 24 fup(i,1,n) { 25 re int l=read(),r=i; 26 sum[i]=sum[i-1]+(l==r); 27 if(l>r) swap(l,r); 28 wtf[l+r].push_back(mp(r,l)); 29 } 30 if(sum[n]==n) std::cout<<sum[n]<<std::endl,exit(0); 31 re int ans=0; 32 fup(i,1,n<<1) if(wtf[i].size()!=0) { 33 std::sort(wtf[i].begin(),wtf[i].end()); 34 fup(j,0,wtf[i].size()-1) { 35 re int l=wtf[i][j].second; 36 re int r=wtf[i][j].first; 37 ans=std::max(ans,sum[n]-sum[r]+sum[l-1]+j+1); 38 } 39 } 40 std::cout<<ans<<std::endl; 41 }
T2. 走格子
考试时根本没打,真没想到这么水...
建图跑spfa就ojbk..
考虑如何建图.
首先相邻边可连,然后就是传送门的使用.
可以发现最佳食用方法是由离自己当前位置最近的墙biu~然后穿过去,所以需要 bfs (或其他)处理离自己最近的墙,建当前位置经墙到别的位置的边.(话说这种题还真好玩虽然不善良
1 #include <queue> 2 #include <cstdio> 3 #include <vector> 4 #include <cstring> 5 #include <iostream> 6 #include <algorithm> 7 #define QAQ 502 8 #define re register 9 #define fup(i,a,b) for(re int i=a;i<=b;++i) 10 #define fdn(i,a,b) for(re int i=a;i>=b;--i) 11 using namespace std; 12 int n,m,st,ed; 13 int v[QAQ*QAQ]; 14 int diss[QAQ*QAQ]; 15 char map[QAQ][QAQ]; 16 int dis[QAQ][QAQ]; 17 int upto[QAQ][QAQ]; 18 int lfto[QAQ][QAQ]; 19 int rgto[QAQ][QAQ]; 20 int dnto[QAQ][QAQ]; 21 vector< pair<int, int> >wtf[QAQ*QAQ]; 22 inline int read() { 23 re int x(0),f(1);re char ch=getchar(); 24 while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } 25 while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); } 26 return x*f; 27 } 28 queue< pair<int, int> >qwq; 29 inline int Get_id(int x,int y) { 30 return (x-1)*m+y; 31 } 32 inline void Try_push(int x,int y,int ds) { 33 if(map[x][y]=='.'&&!dis[x][y]) 34 dis[x][y]=ds,qwq.push(make_pair(x,y)); 35 } 36 int main() { 37 n=read(),m=read(); 38 fup(i,1,n) scanf("%s",map[i]+1); 39 fup(i,1,n) fup(j,1,m) { 40 if(map[i][j]=='#') qwq.push(make_pair(i,j)); 41 if(map[i][j]=='C') map[i][j]='.',st=Get_id(i,j); 42 else if(map[i][j]=='F') map[i][j]='.',ed=Get_id(i,j); 43 } 44 //while(!qwq.size())嘤??? 45 while(qwq.size()) { 46 re int x=qwq.front().first; 47 re int y=qwq.front().second; 48 qwq.pop(); 49 Try_push(x+1,y,dis[x][y]+1); 50 Try_push(x-1,y,dis[x][y]+1); 51 Try_push(x,y+1,dis[x][y]+1); 52 Try_push(x,y-1,dis[x][y]+1); 53 } 54 fup(i,1,n) fup(j,1,m) if(map[i][j]=='.') { 55 if (map[i-1][j]=='#') upto[i][j]=Get_id(i,j); 56 else upto[i][j]=upto[i-1][j]; 57 if (map[i][j-1]=='#') lfto[i][j]=Get_id(i,j); 58 else lfto[i][j]=lfto[i][j-1]; 59 } 60 fdn(i,n,1) fdn(j,m,1) if(map[i][j]=='.') { 61 if (map[i+1][j]=='#') dnto[i][j]=Get_id(i,j); 62 else dnto[i][j]=dnto[i+1][j]; 63 if (map[i][j+1]=='#') rgto[i][j]=Get_id(i,j); 64 else rgto[i][j]=rgto[i][j+1]; 65 } 66 fup(i,1,n) fup(j,1,m) if(map[i][j]=='.') { 67 if (map[i][j+1]=='.') wtf[Get_id(i,j)].push_back(make_pair(Get_id(i,j+1),1)), 68 wtf[Get_id(i,j+1)].push_back(make_pair(Get_id(i,j),1)); 69 if (map[i+1][j]=='.') wtf[Get_id(i,j)].push_back(make_pair(Get_id(i+1,j),1)), 70 wtf[Get_id(i+1,j)].push_back(make_pair(Get_id(i,j),1)); 71 if (upto[i][j]!=Get_id(i,j)) wtf[Get_id(i,j)].push_back(make_pair(upto[i][j],dis[i][j])); 72 if (dnto[i][j]!=Get_id(i,j)) wtf[Get_id(i,j)].push_back(make_pair(dnto[i][j],dis[i][j])); 73 if (lfto[i][j]!=Get_id(i,j)) wtf[Get_id(i,j)].push_back(make_pair(lfto[i][j],dis[i][j])); 74 if (rgto[i][j]!=Get_id(i,j)) wtf[Get_id(i,j)].push_back(make_pair(rgto[i][j],dis[i][j])); 75 } 76 memset(diss,0x3f,sizeof diss); 77 memset(v,0,sizeof v);diss[st]=0; 78 queue<int>qaq; 79 qaq.push(st),v[st]=1; 80 while(qaq.size()) { 81 re int x=qaq.front(); 82 qaq.pop();v[x]=0; 83 if (wtf[x].size()) 84 fup(i,0,wtf[x].size()-1) { 85 re int y=wtf[x][i].first; 86 re int d=wtf[x][i].second; 87 if (diss[y]>diss[x]+d) { 88 diss[y]=diss[x]+d; 89 if (v[y])continue; 90 qaq.push(y),v[y]=1; 91 } 92 } 93 } 94 printf("%d\n",diss[ed]); 95 }
T3. 柱状图
我才不会说我和上次T1一样推了半年的柿子QAQ(最后5分钟打了个过不了样例的暴力骗到了15分
然而正解和数学柿子没卵关系嘤
首先这是一个单谷函数
设 f(x) 代表最高柱子高度为 x 时的调整所需花费。显然,当 x 取到一个恰当的值的时候,可以使得花费最小,当然,这样的值可能有很多个。但是不难发现只要任何一个其他的x'不能取得更优的值,就可以保证这是一个单谷函数(由于相邻的柱子高度差只能为1)(w又颓的网上证明
所以可以三分.
所以枚举最高点,三分高度并判定 就可以 n^2logn 得到 60 分的好成绩.....
考虑如何优化 三分求解时利用两个树状数组来维护最高点两边的关键值,然后利用树状数组的求前缀和功能计算花费即可
$\left [ cnt_l*(h_x-x)-\sum_{i=1}^{pos}(h_i-i) \right ] + \left [ \sum_{i=pos+1}^{n}(h_i-i)-cnt_r*(h_x-x) \right ]$
以上为左侧
$\left [ cnt_l*(h_x+x)-\sum_{i=1}^{pos}(h_i+i) \right ] + \left [ \sum_{i=pos+1}^{n}(h_i+i)-cnt_r*(h_x+x) \right ]$
以上为右侧
cntl 为关键值小于 h[x]-x ( h[x]+x ) 并且下标也小于 x 的数量 cntr关键值大于 h[x]-x ( h[x]+x ) 并且下标也小于 x 的数量
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #define QAQ 100005 6 #define re register 7 #define int long long 8 #define lowbit(x) x&-x 9 #define pait pair<int,int> 10 #define mp(a,b) make_pair(a,b) 11 #define fup(i,a,b) for(re int i=a;i<=b;++i) 12 #define fdn(i,a,b) for(re int i=a;i>=b;--i) 13 using namespace std; 14 int n,ans,a[QAQ],rkl[QAQ],rkr[QAQ]; 15 inline int read() { 16 re int x(0),f(1);re char ch=getchar(); 17 while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } 18 while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); } 19 return x*f; 20 } 21 struct node { 22 int val,id; 23 friend bool operator < (node a,node b) { 24 return a.val < b.val; 25 } 26 }l[QAQ],r[QAQ]; 27 pait operator + (pait a,pait b) { 28 return mp(a.first+b.first,a.second+b.second); 29 } 30 pait operator - (pait a,pait b) { 31 return mp(a.first-b.first,a.second-b.second); 32 } 33 struct tree { 34 int sum[QAQ],cnt[QAQ]; 35 inline void insert(re int x,pait now) { 36 for(;x<=n;x+=lowbit(x)) 37 sum[x]+=now.first, 38 cnt[x]+=now.second; 39 } 40 inline pait query_val(re int x) { 41 pait ans=mp(0,0); 42 for(;x;x-=lowbit(x)) 43 ans=ans+mp(sum[x],cnt[x]); 44 return ans; 45 } 46 inline pait query_line(re int l,re int r) { 47 if(l>r) return mp(0,0); 48 return query_val(r)-query_val(l-1); 49 } 50 }Right,Left; 51 int find(node *what,re int dat) { 52 re int l=1,r=n,mid; 53 while(mid=l+r>>1,l+1<r) { 54 if(what[mid].val>dat) r=mid; 55 else l=mid; 56 } 57 if(what[r].val<=dat) return r; 58 if(what[l].val<=dat) return l; 59 return 0; 60 } 61 int calc(re int id,re int high) { 62 re int res=abs(high-a[id]);re pait cost; 63 re int pos=find(l,high-id); 64 cost=Left.query_val(pos); 65 res+=(high-id)*cost.second-cost.first; 66 cost=Left.query_line(pos+1,n); 67 res+=cost.first-(high-id)*cost.second; 68 pos=find(r,high+id); 69 cost=Right.query_val(pos); 70 res+=(high+id)*cost.second-cost.first; 71 cost=Right.query_line(pos+1,n); 72 res+=cost.first-(high+id)*cost.second; 73 return res; 74 } 75 main() { 76 n=read();re int maxx=0,ans=0x7f7f7f7f7f7f7f7f; 77 fup(i,1,n) a[i]=read(),maxx=max(maxx,a[i]); 78 fup(i,1,n) 79 l[i]=(node){ a[i] - i, i }, 80 r[i]=(node){ a[i] + i, i }; 81 sort(l+1,l+n+1),sort(r+1,r+n+1); 82 fup(i,1,n) 83 rkl[l[i].id] = i, 84 rkr[r[i].id] = i; 85 fup(i,1,n) Right.insert(rkr[i],mp(r[rkr[i]].val,1)); 86 fup(i,1,n) { 87 Right.insert(rkr[i],mp(-r[rkr[i]].val,-1)); 88 re int ll=max(i,n-i+1),rr=maxx+n; 89 while(ll+1<rr){ 90 re int mid=(ll+rr)>>1; 91 if(calc(i,mid-1)>=calc(i,mid)) ll=mid; 92 else rr=mid; 93 } 94 ans=min(ans,calc(i,ll)); ans=min(ans,calc(i,rr)); 95 Left.insert(rkl[i],mp(l[rkl[i]].val,1)); 96 } std::cout<<ans<<std::endl; 97 }
(话说为什么不打模拟退火呢?