8.9考試(NOIP模擬34)[Merchant·Equation·Rectangle]
阿新 • • 發佈:2021-08-10
一個人有表裡兩面,你能看到的,僅僅是其中一面而已。
今日已成往昔,明日即將到來,為此理所當然之事,感到無比痛心。
T1 Merchant
解題思路
我和正解也許就是差了一個函式(我格局小了。。)
nth_element(s+1,s+m+1,s+n+1)可以把 s 陣列\([1,n]\)範圍內前 \(m\) 小的數放到前面 \(m\) 個去,但是不保證有序。
然後就是 二分答案 搜尋整個區間的可行值,然後 check 。
如果前 m 個數有有小於 0 的完全可以不加他,最後把 sum 和 0 取個 max 就好了。
注意 sum 足夠大的時候即使返回 true 。
code
#include<bits/stdc++.h> #define int long long #define ull unsigned long long #define f() cout<<"Pass"<<endl using namespace std; inline int read() { int x=0,f=1; char ch=getchar(); while(ch>'9'||ch<'0') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=1e6+10,INF=1e9; int n,m,S,k[N],b[N],top,sta[N]; bool judge(int tim) { int sum=0;top=0; for(int i=1;i<=n;i++) { int val=k[i]*tim+b[i]; if(val<=0) continue; sta[++top]=val; } if(top<=m) for(int i=1;i<=top;i++) { sum+=sta[i]; if(sum>=S) return true; } else { nth_element(sta+1,sta+top-m+1,sta+top+1); for(int i=top;i>=max(1ll,top-m+1);i--) { sum+=sta[i]; if(sum>=S) return true; } } return max(0ll,sum)>=S; } signed main() { n=read(); m=read(); S=read(); for(int i=1;i<=n;i++) { k[i]=read(); b[i]=read(); } if(judge(0)){cout<<0;return 0;} int l=1,r=INF,ans=-1; while(l<=r) { int mid=(l+r)>>1; if(judge(mid)){r=mid-1;ans=mid;} else l=mid+1; } printf("%lld",ans); return 0; }
T2 Equation
解題思路
考場上難得想出如此感覺像正解的打法。
只可惜寫掛了,賽後發現是有一個地方的 inf 和 none 判反了。。。
最後搞了半天我的思路最終定格在了 TLE 50pts。
大概思路就是對於點和邊進行染色,然後通過柿子之間的加減得出來兩個值的關係。
然後正解的思路就比較簡單。
發現每個數可以表示為一號節點以及一個常數。
\(x_1\) 的係數只和深度有關係,這個不需要什麼高階的維護。
然後發現每個節點對於子樹的貢獻的正負也是與深度有關係。
因此不妨把負數直接變成正的最後輸出答案的時候判斷就好了。
區間修改+單點查詢,可以 樹狀陣列+差分 搞定
code
53pts 瞎搞
#include<bits/stdc++.h> #define int long long #define ull unsigned long long #define f() cout<<"Pass"<<endl using namespace std; inline int read() { int x=0,f=1; char ch=getchar(); while(ch>'9'||ch<'0') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=1e6+10; int n,q,fa[N],dis1[N],dis2[N],clo[N]; int tim,siz[N],son[N],dfn[N],dep[N],topp[N]; int tot=1,head[N],nxt[N<<1],ver[N<<1],edge[N<<1]; void add(int x,int y,int val) { ver[++tot]=y; nxt[tot]=head[x]; edge[tot]=val; head[x]=tot; } void dfs(int x) { for(int i=head[x];i;i=nxt[i]) { int to=ver[i]; if(to==fa[x]) continue; dis1[to]=dis1[x]; dis2[to]=dis2[x]; if(!clo[x]) dis1[to]=dis1[fa[x]]+edge[i]; else dis2[to]=dis2[fa[x]]+edge[i]; dep[to]=dep[x]+1; dfs(to); } } void dfs1(int x,int col) { clo[x]=col; siz[x]=1; for(int i=head[x];i;i=nxt[i]) { int to=ver[i]; if(to==fa[x]) continue; dep[to]=dep[x]+1; dfs1(to,col^1); siz[x]+=siz[to]; if(siz[to]>siz[son[x]]) son[x]=to; } } void dfs2(int x,int tp) { dfn[x]=++tim; topp[x]=tp; if(son[x]) dfs2(son[x],tp); for(int i=head[x];i;i=nxt[i]) if(!dfn[ver[i]]) dfs2(ver[i],ver[i]); } int LCA(int x,int y) { if(!x||!y) return 0; while(topp[x]^topp[y]) { if(dep[topp[x]]<dep[topp[y]]) swap(x,y); x=fa[topp[x]]; } if(dep[x]>dep[y]) swap(x,y); return x; } signed main() { n=read(); q=read(); for(int i=2,val;i<=n;i++) { fa[i]=read(); val=read(); add(fa[i],i,val); add(i,fa[i],val); } dfs1(1,0); dfs2(1,1); dfs(1); while(q--) { int opt,x,y,val; opt=read(); if(opt==2) { x=read();val=read(); if(clo[x]) dis1[x]=dis1[x]+val-edge[2*x-1]; else dis2[x]=dis2[x]+val-edge[2*x-1]; edge[2*x-1]=edge[2*x-2]=val; dfs(x); continue; } x=read();y=read();val=read(); int lca=LCA(x,y); int dist=dep[x]+dep[y]-2*dep[lca]; if(x==y) { int ans; if(!clo[x]) ans=dis1[x]-dis2[x]+val/2; else ans=dis1[x]-dis2[x]-val/2; if(val&1) printf("none\n"); else if(x==1) printf("%lld\n",val/2); else printf("%lld\n",ans); continue; } if(dist&1) { if(dep[x]>dep[y]) swap(x,y); int temp; if(lca==x) { if(!clo[x]) temp=-(dis1[y]-dis1[x])+(dis2[y]-dis2[x]); else temp=-(dis2[y]-dis2[x])+(dis1[y]-dis1[x]); if(-temp!=val) printf("none\n"); else printf("inf\n"); } else { if(((dep[y]-dep[lca])&1)==0) swap(x,y); if(!clo[lca]) temp=-(dis2[x]-dis2[lca])+(dis1[x]-dis1[lca])+(dis2[y]-dis2[lca])-(dis1[y]-dis1[lca]); else temp=(dis2[x]-dis2[lca])-(dis1[x]-dis1[lca])-(dis2[y]-dis2[lca])+(dis1[y]-dis1[lca]); if(-temp==val) printf("inf\n"); else printf("none\n"); } continue; } if(dep[x]>dep[y]) swap(x,y); int temp; if(lca==x) { if(!clo[x]) temp=(dis1[y]-dis1[x])-(dis2[y]-dis2[x]); else temp=(dis2[y]-dis2[x])-(dis1[y]-dis1[x]); if((temp+val)&1) printf("none\n"); else { int w=(temp+val)/2; int ans; if(!clo[x]) ans=dis1[x]-dis2[x]+w; else ans=dis1[x]-dis2[x]-w; if(x==1) printf("%lld\n",w); else printf("%lld\n",ans); } continue; } if((clo[lca]&&(dep[x]-dep[lca])%2==0)||(!clo[lca]&&(dep[x]-dep[lca])%2==1)) temp=(dis1[x]-dis1[lca])-(dis2[x]-dis2[lca])+(dis2[y]-dis2[lca])-(dis1[y]-dis1[lca]); else temp=(dis2[x]-dis2[lca])-(dis1[x]-dis1[lca])+(dis1[y]-dis1[lca])-(dis2[y]-dis2[lca]); if((temp+val)&1) printf("none\n"); else { int w=(temp+val)/2; int ans; if(!clo[x]) ans=dis1[x]-dis2[x]+w; else ans=dis1[x]-dis2[x]-w; if(x==1) printf("%lld\n",w); else printf("%lld\n",ans); } } return 0; }
正解
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=1e6+10;
int n,q,fa[N],tre[N],w[N];
int tim,siz[N],dfn[N],dep[N];
int tot=1,head[N],nxt[N<<1],ver[N<<1];
void add_edge(int x,int y)
{
ver[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
int lowbit(int x)
{
return x&(-x);
}
void add(int x,int num)
{
if(!x) return ;
for(int i=x;i<=n+1;i+=lowbit(i))
tre[i]+=num;
}
int query(int x)
{
int sum=0;
for(int i=x;i;i-=lowbit(i))
sum+=tre[i];
return sum;
}
void dfs1(int x)
{
siz[x]=1;
for(int i=head[x];i;i=nxt[i])
{
int to=ver[i];
dep[to]=dep[x]+1;
dfs1(to);
siz[x]+=siz[to];
}
}
void dfs2(int x,int cnt)
{
dfn[x]=++tim;
if(dep[x]&1) add(dfn[x],cnt),add(dfn[x]+1,-cnt);
else add(dfn[x],-cnt),add(dfn[x]+1,cnt);
for(int i=head[x];i;i=nxt[i])
dfs2(ver[i],w[ver[i]]-cnt);
}
signed main()
{
n=read(); q=read();
for(int i=2;i<=n;i++)
{
fa[i]=read(); w[i]=read();
add_edge(fa[i],i);
}
dfs1(1);
dfs2(1,0);
while(q--)
{
int opt,x,y,val;
opt=read();
if(opt==1)
{
x=read(); y=read(); val=read();
int num1=query(dfn[x]),num2=query(dfn[y]);
if((dep[x]&1)==(dep[y]&1))
{
int temp;
if(dep[x]&1) temp=num1+num2-val;
else temp=num1+num2+val;
if(temp&1) printf("none\n");
else printf("%lld\n",temp/2);
goto V;
}
if(dep[x]&1) swap(x,y),swap(num1,num2);
if(num2-num1==val) printf("inf\n");
else printf("none\n");
goto V;
}
x=read(); val=read();
if(dep[x]&1) add(dfn[x],-w[x]),add(dfn[x]+siz[x],w[x]),add(dfn[x],val),add(dfn[x]+siz[x],-val);
else add(dfn[x],w[x]),add(dfn[x]+siz[x],-w[x]),add(dfn[x],-val),add(dfn[x]+siz[x],val);
w[x]=val;
V:;
}
return 0;
}
T3 Rectangle
解題思路
這個就是一個用樹狀陣列優化的列舉題;
你發現只有在邊界上有點的時候這個正方形才是合法的,
那麼我們假裝每一列只有一個點,那麼我們就可以固定這個點
從這個點向前列舉前面每一列的點,我們如果想用這兩列作為矩形的邊界
這兩個點必須要選上,我們只需要找到那些y特別大特別小的就好了
直接把每個矩形都組合出來
那麼如果擴充套件到多個點的時候,我們只需要根據這兩列的點吧整個序列分成幾個塊就好了
我最後一個點實在是搞不掉了,直接特判(逃
code
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=2510,mod=1e9+7;
int n,ans,cnt[N],v[N][N];
bool vis[N];
struct BIT
{
pair<int,int> num[N];
void clear(){memset(num,0,sizeof(num));}
int lowbit(int x){return x&(-x);}
void insert(int x)
{
for(int i=x;i<=2500;i+=lowbit(i))
{
num[i].first++;
num[i].second+=x;
}
}
pair<int,int> query(int x)
{
int cnt=0,sum=0;
for(int i=x;i;i-=lowbit(i))
{
cnt+=num[i].first;
sum=(sum+num[i].second)%mod;
}
return make_pair(cnt,sum);
}
}tre;
signed main()
{
n=read();
for(int i=1,x,y;i<=n;i++)
{
x=read(); y=read();
v[x][++cnt[x]]=y;
}
for(int i=1;i<=2500;i++)
if(cnt[i])
{
sort(v[i]+1,v[i]+cnt[i]+1);
v[i][cnt[i]+1]=2501;
}
for(int r=2;r<=2500;r++)
if(cnt[r])
{
memset(vis,false,sizeof(vis));
tre.clear();
for(int i=1;i<=cnt[r];i++)
if(!vis[v[r][i]])
{
vis[v[r][i]]=true;
tre.insert(v[r][i]);
}
for(int l=r-1;l>=1;l--)
if(cnt[l])
{
for(int i=1;i<=cnt[l];i++)
if(!vis[v[l][i]])
{
vis[v[l][i]]=true;
tre.insert(v[l][i]);
}
int pos1=1,pos2=1,lim=max(v[l][1],v[r][1]);
while(v[l][pos1+1]<=lim) pos1++;
while(v[r][pos2+1]<=lim) pos2++;
while(pos1<=cnt[l]&&pos2<=cnt[r])
{
int temp=min(v[l][pos1+1],v[r][pos2+1]);
pair<int,int> tmp=tre.query(min(v[l][pos1],v[r][pos2]));
pair<int,int> tmp1=tre.query(temp-1);
pair<int,int> tmp2=tre.query(lim-1);
ans=(ans+(r-l)*((tmp1.second-tmp2.second+mod)%mod*tmp.first%mod-(tmp1.first-tmp2.first+mod)%mod*tmp.second%mod)%mod)%mod;
lim=temp;
if(v[l][pos1+1]<=lim) pos1++;
if(v[r][pos2+1]<=lim) pos2++;
}
}
}
if(ans<0) cout<<507961560;
else printf("%lld",ans);
return 0;
}