NOIP模拟测试14「旋转子段·走格子·柱状图」
旋轉(zhuǎn)子段
連60分都沒想,考試一直肝t3,t2,沒想到t1最簡單
我一直以為t1很難,看了題解發(fā)現(xiàn)也就那樣
題解
性質(zhì)1
一個(gè)包含a[i]旋轉(zhuǎn)區(qū)間值域范圍最多為min(a[i],i)----max(a[i],i)
感性理解
舉個(gè)例子,例如3 7 1 4 5 6 2
這個(gè)子段包含a[2]的最大為值域范圍2----7
具體證明我不會(huì)
性質(zhì)2
翻轉(zhuǎn)后滿足固定點(diǎn)對(duì)的點(diǎn)滿足
a[i]+i==a[j]+j
證明
因?yàn)榉D(zhuǎn)之前a[i]==j&&a[j]==i才滿足翻轉(zhuǎn)之后都構(gòu)成點(diǎn)對(duì)
移項(xiàng)得到a[i]+i==a[j]+j
有了這兩條性質(zhì)我們可以得到一個(gè)$n^2$算法
for(ll i=1;i<=n;i++){tot=0;for(ll j=min(i,a[i]);j<=max(i,a[i]);j++)if(a[j]+j==a[i]+i)tot++; }得到tot最大值輸出即可
70分代碼
#include<bits/stdc++.h> using namespace std; #define ll long long #define A 1010101 ll f[A],a[A],sum[A]; ll n,ans=-1,tot=0; vector<ll>too[501010]; int main(){scanf("%lld",&n);for(ll i=1;i<=n;i++){scanf("%lld",&a[i]);sum[i]=sum[i-1];if(a[i]==i) sum[i]++;}for(ll i=1;i<=n;i++){tot=0;for(ll j=min(i,a[i]);j<=max(i,a[i]);j++){if(a[j]+j==a[i]+i){tot++;}} // printf("n=%lld max=%lld min=%lld i=%lld tot=%lld\n",n,max(i,a[i]),min(i,a[i]),i,tot);ans=max(tot+sum[n]-sum[max(i,a[i])]+sum[min(i,a[i])-1],ans);}printf("%lld\n",ans); } View Code100分
莫隊(duì)維護(hù)一下詢問,需要卡常,卡常到自閉,fh卡常大師
分塊0.53最優(yōu)
#include<bits/stdc++.h> using namespace std; #define ll int const int A=1010101,L=1<<20|1; #define getchar() ((S==T&&(T=(S=buf)+fread(buf,1,L,stdin),S==T))?EOF:*S++) ll f[A],a[A],sum[A],tong[A],belong[A]; ll n,ans=-1,l=1,r=0,ou=0,block; char buf[L],*S,*T; struct moo{ll zhong,r,l,a;friend bool operator < (moo a,moo b){return ((belong[a.l]^belong[b.l]))?a.l<b.l:((belong[a.l]&1)?a.r<b.r:a.r>b.r);} }mo[A]; inline ll read(){ll x=0;char c=getchar();while(!isdigit(c))c=getchar();while(isdigit(c))x=(x<<1)+(x<<3)+(c^48),c=getchar();return x; } int main(){n=read();block=pow(n,0.53);for(register ll i=1;i<=n;i++){a[i]=read();sum[i]=sum[i-1];if(!(a[i]^i)) sum[i]++;belong[i]=(i-1)/block+1;}for(register ll i=1;i<=n;i++){mo[i].zhong=i;mo[i].r=max(i,a[i]);mo[i].l=min(i,a[i]);mo[i].a=a[i];}sort(mo+1,mo+n+1);for(register ll i=1;i<=n;i++){while(l>mo[i].l) tong[l-1+a[l-1]]++,l--;while(l<mo[i].l) tong[l+a[l]]--,l++;while(r>mo[i].r) tong[r+a[r]]--,r--;while(r<mo[i].r) tong[r+1+a[r+1]]++,r++;ans=max(tong[mo[i].zhong+mo[i].a]+sum[n]-sum[mo[i].r]+sum[mo[i].l-1],ans);}printf("%d",ans); } View Code走格子
顯然貪心有門走門不對(duì)一個(gè)稍簡單的數(shù)據(jù)就可以卡掉你
7 8 ######## ##.F#..# #...C..# ##..#..# ##.....# #..#...# ########那怎么辦,只能走八個(gè)方向爆搜嗎?
顯然可以最短路!
從每個(gè)墻開始搜直接得到每個(gè)點(diǎn)到墻最短距離,然后每兩相鄰點(diǎn)之間建邊,點(diǎn)墻之間建邊
例如?????????????? (墻)
|
50
????? ? |
(墻)-----21------Q-------------500000000-------(墻)
|
|
600
|
(墻)
我們只需要將Q與四個(gè)墻方向邊權(quán)都設(shè)置為21即可.(例如可以在2打傳送門? 然后在4打傳送門從2傳送到4,那么所有最小代價(jià)都為21)
很簡單對(duì)不對(duì),直接跑最短路就行了
保證最短路會(huì)松弛掉一些不可行解
例如
(墻)
? |
50
(墻)|
(墻)------21--Q-------500000--(墻)
|
50
|
(終點(diǎn))
向上走一步再打傳送門會(huì)松弛掉21這條邊
代碼
#include<bits/stdc++.h> using namespace std; #define ll long long #define A 5010101 #define py printf("toot\n") #define fr first #define se second #define mp(x,y) make_pair(x,y) ll zh[610][610],top[610][610],low[610][610],zuo[610][610],you[610][610],bs[610][610],head[A],nxt[A],ver[A],edg[A],dis[A]; const ll nowx[5]={0,0,0,1,-1}; const ll nowy[5]={0,1,-1,0,0}; bool vis[A]; ll n,m,zhongx,zhongy,qix,qiy,ttt=0,tot=0; deque<pair<ll,ll> >q,toot; char s[610][610]; ll id(ll i,ll j){return (i-1)*m+j; } void add(ll x,ll y,ll z){nxt[++tot]=head[x],head[x]=tot,ver[tot]=y,edg[tot]=z;return ; } void ins(ll x,ll y,ll d){if(!bs[x][y]&&s[x][y]=='.'){bs[x][y]=d;q.push_back(mp(x,y));} } void bfs(){while(!q.empty()){ll kx=q.front().fr,ky=q.front().se;q.pop_front(); // py;for(ll i=1;i<=4;i++){ins(kx+nowx[i],ky+nowy[i],bs[kx][ky]+1);}} } void init(){for(ll i=1;i<=n;i++)for(ll j=1;j<=m;j++){if(s[i][j]=='#') continue;if(s[i][j-1]=='#') zuo[i][j]=id(i,j);else zuo[i][j]=zuo[i][j-1];if(s[i-1][j]=='#') top[i][j]=id(i,j);else top[i][j]=top[i-1][j];}for(ll i=n;i>=1;i--)for(ll j=m;j>=1;j--){if(s[i][j]=='#') continue;if(s[i][j+1]=='#') you[i][j]=id(i,j);else you[i][j]=you[i][j+1];if(s[i+1][j]=='#') low[i][j]=id(i,j);else low[i][j]=low[i+1][j];} } void addb(){for(ll i=1;i<=n;i++)for(ll j=1;j<=m;j++){if(s[i][j]=='#') continue;ll d=id(i,j);if(s[i+1][j]=='.') add(d,id(i+1,j),1),add(id(i+1,j),d,1);if(s[i][j+1]=='.') add(d,id(i,j+1),1),add(id(i,j+1),d,1);if(zuo[i][j]!=d)add(d,zuo[i][j],bs[i][j]);if(you[i][j]!=d)add(d,you[i][j],bs[i][j]);if(top[i][j]!=d)add(d,top[i][j],bs[i][j]);if(low[i][j]!=d)add(d,low[i][j],bs[i][j]);} } void spfa(ll o){vis[o]=1;memset(dis,0x7f,sizeof(dis));dis[o]=0;deque<ll> toot;toot.push_back(o);while(!toot.empty()){ll x=toot.front();toot.pop_front();for(ll i=head[x];i;i=nxt[i]){ll y=ver[i];if(dis[y]>dis[x]+edg[i]){dis[y]=dis[x]+edg[i];if(!vis[y]){vis[y]=1;toot.push_back(y);}}}vis[x]=0;} } int main(){scanf("%lld%lld",&n,&m);for(ll i=1;i<=n;i++){scanf("%s",s[i]+1);for(ll j=1;j<=m;j++){if(s[i][j]=='#'){q.push_back(mp(i,j));}else if(s[i][j]=='C'){s[i][j]='.';qix=i;qiy=j;}if(s[i][j]=='F'){s[i][j]='.';zhongx=i;zhongy=j;}}}bfs(),init(),addb(),spfa(id(qix,qiy));if(dis[id(zhongx,zhongy)]>=1202134)printf("no\n");else printf("%lld\n",dis[id(zhongx,zhongy)]); } View Code?柱狀圖
模擬退火板子題,非常板子
模擬退火最吼了
即使是板子我也要說說
首先關(guān)于
nth_element(s+1,s+mid,s+n+1);為什么要求出中位數(shù),
前置知識(shí)
坐標(biāo)軸上有很多點(diǎn),點(diǎn)與點(diǎn)之間有一個(gè)距離,你將所有點(diǎn)移到同一個(gè)點(diǎn)最小花費(fèi)
顯然是移到中位數(shù)的點(diǎn)
那么應(yīng)用到這個(gè)題呢?
你可以將題目要求轉(zhuǎn)化,首先全部移到同一水平線上,然后再加出值
比它高的降低,比它矮的升高,換成坐標(biāo)軸我們就用到了中位數(shù)
然后
if(tmpans<nowans||exp(-D/T)*RAND_MAX>rand())為什么是
exp(-D/T)*RAND_MAX>rand()不是
exp(D/T)*RAND_MAX>rand()問的好啊!
首先我們?nèi)绻?dāng)前解優(yōu)那么你會(huì)通過tmpans<nowans跳過
然后如果當(dāng)前解不優(yōu)D一定是負(fù)的,如果D為負(fù)的那么D越小-D越大.D小代表當(dāng)前解非常差,讓它變成其他解概率更大
?
#include<bits/stdc++.h> using namespace std; #define ll long long #define A 1010101 const double eps=1e-5; const double delta=0.98; const double fj=1; ll n,ans=0x7ffffffffffffff; ll s[A],h[A]; ll check(ll pos){for(ll j=1;j<=n;j++)s[j]=h[j]+abs(pos-j);ll mid=n+1>>1;nth_element(s+1,s+mid,s+n+1);ll val=s[mid];ll tot=0;if(val<max(pos,n-pos+1))val=max(pos,n-pos+1);for(ll i=1;i<=n;i++)tot+=abs(s[i]-val);return tot; } int main(){srand(time(0));scanf("%lld",&n);for(ll i=1;i<=n;i++){scanf("%lld",&h[i]);}double T=1000;ll now=(n+1)>>1;ll nowans=check(now);while(T>eps){ll tmp=now+(2ll*rand()-RAND_MAX)*T*0.000001;tmp=(tmp%n+n-1)%n+1;ll tmpans=check(tmp),D=tmpans-nowans;if(tmpans<nowans||exp(-D/T)*RAND_MAX>rand())nowans=tmpans,now=tmp;if(tmpans<ans) ans=tmpans;T*=delta;}printf("%lld\n",ans); } View Code?
轉(zhuǎn)載于:https://www.cnblogs.com/znsbc-13/p/11319578.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的NOIP模拟测试14「旋转子段·走格子·柱状图」的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2021年,会不会有iPhone SE3
- 下一篇: 检测域名是否到期