noip模擬40[雙指標被拋棄了....]
阿新 • • 發佈:2021-08-20
noip模擬40 solutions
怎麼說呢,我這兩天用單調指標用的非常的順手
第一題證都沒證就單調指標去了,導致我抱零了
所以我以後用之前一定要證一下,
關於我做題老是想不到正解這件事,我已經不糾結了,因為我完全可以亂搞出奇跡
因為第二題我亂搞+卡時,搞到了70pts
T1 送花
這個就是列舉右端點,對左區間進行更新,這個有得天獨厚的優勢
因為一旦出現重複的東西,我就直接不要這個貢獻了
線上段樹上的操作就是對上上次出現的到上次出現的區間減去貢獻
在上次出現到這次出現的區間內加上貢獻
AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=1e6+5;
int n,m,c[N];
ll d[N];
struct XDS{
#define ls x<<1
#define rs x<<1|1
ll now[N*4],laz[N*4];
void pushup(int x){
now[x]=max(now[ls],now[rs]);
return ;
}
void pushdown(int x){
//cout<<x<<endl;
if(!laz[x])return ;
laz[ls]+=laz[x];
laz[rs]+=laz[x];
now[ls]+=laz[x];
now[rs]+=laz[x];
laz[x]=0;
return ;
}
void ins(int x,int l,int r,int ql,int qr,ll v){
//cout<<x<<" "<<l<<" "<<r<<" "<<ql<<" "<<qr<<endl;
if(ql>r||qr<l||ql>qr)return ;
if(ql<=l&&r<=qr){
now[x]+=v;laz[x]+=v;
return ;
}
pushdown(x);
int mid=l+r>>1;
if(ql<=mid)ins(ls,l,mid,ql,qr,v);
if(qr>mid)ins(rs,mid+1,r,ql,qr,v);
pushup(x);
return ;
}
#undef ls
#undef rs
}xds;
int pre[N],prx[N];
ll ans;
signed main(){
scanf("%d%d",&n,&m);
for(re i=1;i<=n;i++)scanf("%d",&c[i]);
for(re i=1;i<=m;i++)scanf("%lld",&d[i]);
for(re i=1;i<=n;i++){
xds.ins(1,1,n,prx[c[i]]+1,pre[c[i]],-d[c[i]]);
xds.ins(1,1,n,pre[c[i]]+1,i,d[c[i]]);
prx[c[i]]=pre[c[i]];
pre[c[i]]=i;
ans=max(ans,xds.now[1]);
}
printf("%lld",ans);
}
T2 星空
這就是我考場出奇跡的題,直接亂搞得到70pts
具體是這樣做的,我一眼看上去,這好像是個最短路誒
最短路的話,直接dij那不就是最好的選擇嘛????
我直接把每一對點的距離放到佇列裡面,額,好像是魔改dij
然後每次提取隊頭,從這兩個端點分別向外擴充套件n個點,得到新的距離,再放到佇列中
這樣的話,保守估計,複雜度應該是\(\mathcal{O(n^3log^3n)}\)的
然後我覺得這樣肯定會T ,所以就加上了一句話
int tim=clock();
if(clock()-tim>800000)break;
然後就成功的卡到了70pts,但是這個是有正確性的,如果陣列可以開出來,就能A
因為每次都是找最短的來更新
70pts
#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=1e5+5;
struct node{
int x,y,dis;
node(){}
node(int a,int b,int c){
x=a;y=b;dis=c;
}
bool operator < (node a)const{
return dis>a.dis;
}
};
priority_queue<node> q;
int n,dit[6005][6005],ans,sum;
struct pot{
int x,y;
pot(){}
}sca[N];
bool vis[6005][6005];
signed main(){
//cout<<((sizeof(vis)+sizeof(dit))>>20)<<endl;
int tim=clock();
scanf("%d",&n);
for(re i=1;i<=n;i++)
scanf("%d%d",&sca[i].x,&sca[i].y);
memset(dit,0x3f,sizeof(dit));
for(re i=1;i<=n;i++){
for(re j=i+1;j<=n;j++){
dit[j][i]=dit[i][j]=abs(abs(sca[i].x-sca[j].x)-abs(sca[i].y-sca[j].y));
q.push(node(i,j,dit[i][j]));
}
}
while(!q.empty()){
if(clock()-tim>800000)break;
int x=q.top().x,y=q.top().y,dis=q.top().dis;q.pop();
if(vis[x][y]||dit[x][y]!=dis)continue;
vis[x][y]=true;
for(re i=1;i<=n;i++){
if(i==x||i==y)continue;
if(vis[i][y])continue;
int tmp=abs(abs(sca[i].x-sca[x].x)-abs(sca[i].y-sca[x].y));
if(tmp+dis<dit[i][y]){
dit[y][i]=dit[i][y]=tmp+dis;
q.push(node(i,y,dit[i][y]));
}
}
for(re i=1;i<=n;i++){
if(i==x||i==y)continue;
if(vis[x][i])continue;
int tmp=abs(abs(sca[i].x-sca[y].x)-abs(sca[i].y-sca[y].y));
if(tmp+dis<dit[x][i]){
dit[x][i]=dit[i][x]=tmp+dis;
q.push(node(i,x,dit[x][i]));
}
}
}
ans=0x3f3f3f3f;
for(re i=1;i<=n;i++)
for(re j=i+1;j<=n;j++)
if(dit[i][j])ans=min(ans,dit[i][j]);
for(re i=1;i<=n;i++)
for(re j=i+1;j<=n;j++)
if(dit[i][j]==ans)sum++;
printf("%d\n%d",ans,sum);
}
其實正解是先轉換座標系,給它斜過來,然後就像題解說的做就好了,
並查集真的挺好用的,然後用vector維護距離為ans1的並查集就行了
轉化座標系是真的妙,自己手摸一下就有了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=1e5+5;
int n;
struct node{
int xp,yp,x,y,id;
node(){}
}sca[N];
struct BSU{
int fa[N],siz[N];
BSU(){for(re i=1;i<=100000;i++)fa[i]=i,siz[i]=1;}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void merge(int x,int y){
if(!x||!y)return ;
int fx=find(x),fy=find(y);
if(fx==fy)return ;
fa[fx]=fy;siz[fy]+=siz[fx];
}
}bsu;
int mpx[N*4],mpy[N*4],bas=2e5+1,ans1=0x3f3f3f3f,ans2=0;
bool cmx(node a,node b){if(a.x!=b.x)return a.x<b.x;return a.y<b.y;}
bool cmy(node a,node b){if(a.y!=b.y)return a.y<b.y;return a.x<b.x;}
vector<pair<int,int> > vec[N*4];
signed main(){
scanf("%d",&n);
for(re i=1;i<=n;i++){
scanf("%d%d",&sca[i].xp,&sca[i].yp);
sca[i].x=sca[i].xp+sca[i].yp;
sca[i].y=sca[i].xp-sca[i].yp;
sca[i].id=i;
}
for(re i=1;i<=n;i++){
int xx=sca[i].x+bas,yy=sca[i].y+bas;
if(mpx[xx])bsu.merge(i,mpx[xx]);
else mpx[xx]=i;
if(mpy[yy])bsu.merge(i,mpy[yy]);
else mpy[yy]=i;
}
sort(sca+1,sca+n+1,cmx);
for(re i=1;i<n;i++){
int tmp=min(abs(sca[i].x-sca[i+1].x),abs(sca[i].y-sca[i+1].y));
int fx=bsu.find(sca[i].id),fy=bsu.find(sca[i+1].id);
vec[tmp].push_back(make_pair(min(fx,fy),max(fx,fy)));
if(tmp)ans1=min(ans1,tmp);
}
sort(sca+1,sca+n+1,cmy);
for(re i=1;i<n;i++){
int tmp=min(abs(sca[i].x-sca[i+1].x),abs(sca[i].y-sca[i+1].y));
int fx=bsu.find(sca[i].id),fy=bsu.find(sca[i+1].id);
vec[tmp].push_back(make_pair(min(fx,fy),max(fx,fy)));
if(tmp)ans1=min(ans1,tmp);
}
printf("%d\n",ans1);
sort(vec[ans1].begin(),vec[ans1].end());
vec[ans1].erase(unique(vec[ans1].begin(),vec[ans1].end()),vec[ans1].end());
//cout<<vec[ans1].size()<<endl;
for(re i=0;i<vec[ans1].size();i++){
if(vec[ans1][i].first==vec[ans1][i].second)continue;
//cout<<vec[ans1][i].first<<" "<<vec[ans1][i].second<<endl;
ans2+=bsu.siz[vec[ans1][i].first]*bsu.siz[vec[ans1][i].second];
}
printf("%d\n",ans2);
}
T3 零一串
這個我也沒有改過,因為,我懶得動了
直接把每個1的移動的序列搞出來
然後就用佇列維護就好了,維護這個序列中0的相對位置
沽~~~~