2021.8.9考试总结[NOIP模拟34]

T1 Merchant


如果$t=0$时不能达到$s$,那么所拿物品的价值一定关于时间单调递增,答案单调。因此可以特判$0$后二分。

用$sort$复杂度被卡,要用$\textit{nth_element}$,相当于$sort$只递归一边,均摊$O(n)$。

$check$时遇到小于零的直接跳过,达到$s$后直接$return$,不然可能爆$\textit{long long}$。

$code:$

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 #define rin register signed
 4 using namespace std;
 5 const int NN=1e6+5;
 6 int n,m,s,spj,ans,l,r=1e9,mid,tmp[NN];
 7 struct line{ int k,b; }ln[NN];
 8 inline bool cmp(line a,line c){ return a.b>c.b;}
 9 inline bool cmpn(int a,int b){ return a>b; }
10 inline int read(){
11     int x=0,f=1; char ch=getchar();
12     while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
13     while(ch<='9'&&ch>='0'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
14     return x*f;
15 }
16 inline void write(int x){
17     char ch[20]; int len=0;
18     if(x<0) x=~x+1, putchar('-');
19     do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x);
20     for(rin i=len-1;i>=0;--i) putchar(ch[i]);
21 }
22 inline bool check(int mid){
23     int res=0;
24     for(int i=1;i<=n;i++) tmp[i]=ln[i].k*mid+ln[i].b;
25     nth_element(tmp+1,tmp+m+1,tmp+n+1,cmpn);
26     for(int i=1;i<=m;i++){ 
27         if(tmp[i]<=0) continue;
28         res+=tmp[i];
29         if(res>=s) return 1;
30     }
31     return 0;
32 }
33 signed main(){
34     n=read(); m=read(); s=read();
35     for(rin i=1;i<=n;i++)
36         ln[i].k=read(), ln[i].b=read();
37     sort(ln+1,ln+n+1,cmp);
38     for(int i=1;i<=m;i++){ 
39         spj+=ln[i].b;
40         if(spj>=s){ puts("0"); return 0; }
41     }
42     while(l<=r){
43         mid=l+r>>1;
44         if(check(mid)) ans=mid, r=mid-1;
45         else l=mid+1;
46     }
47     write(ans); putchar('\n');
48     return 0;
49 }
T1

 

T2 Equation


 可以在$DFS$中求出当前点u与一号节点形成的式子,同时可以通过该点深度得到与一号节点形成的式子是加是减。然后简单消元可以得到想要的方程,直接求解判断即可。

修改时要修改子树中所有节点,在$DFS$序上建两个差分树状数组,一个记加法节点,一个记减法节点,修改时操作相反。

其实一个树状数组也行,用时取负即可。

$code:$

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 const int NN=1e6+5;
 5 int n,q,to[NN<<1],nex[NN<<1],head[NN],num,w[NN],op,u,v,ww;
 6 int typ[NN],dep[NN],siz[NN],dfn[NN],cnt;
 7 struct tr{
 8     int c[NN];
 9     int lowbit(int x){ return x&(-x); }
10     void insert(int val,int pos){
11         while(pos<=n){
12             c[pos]+=val;
13             pos+=lowbit(pos);
14         }
15     }
16     int query(int pos){
17         int res=0;
18         while(pos){
19             res+=c[pos];
20             pos-=lowbit(pos);
21         }
22         return res;
23     }
24 }c[2];
25 inline int read(){
26     int x=0,f=1; char ch=getchar();
27     while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
28     while(ch<='9'&&ch>='0'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 
29     return x*f;
30 }
31 inline void write(int x){
32     char ch[20]; int len=0;
33     if(x<0) x=~x+1, putchar('-');
34     do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x);
35     for(int i=len-1;i>=0;--i) putchar(ch[i]);
36 }
37 inline void add(int a,int b){
38     to[++num]=b; nex[num]=head[a]; head[a]=num;
39     to[++num]=a; nex[num]=head[b]; head[b]=num;
40 }
41 void dfs(int f,int s,int pre){
42     dep[s]=dep[f]+1; siz[s]=1; dfn[s]=++cnt;
43     typ[s]=(dep[s]&1)?0:1;
44     c[typ[s]].insert(pre,dfn[s]);
45     c[typ[s]].insert(-pre,dfn[s]+1);
46     for(int i=head[s];i;i=nex[i]){
47         int v=to[i];
48         if(v==f) continue;
49         dfs(s,v,w[v]-pre);
50         siz[s]+=siz[v];
51     }
52 }
53 void calc(int u,int v,int ww){
54     int tu=typ[u],tv=typ[v],uu;
55     int wu=c[tu].query(dfn[u]);//-c[tu].query(dfn[u]-1);
56     int wv=c[tv].query(dfn[v]);//-c[tv].query(dfn[v]-1);
57     if(tu^tv){ puts((wu+wv)==ww?"inf":"none"); return; }
58     if((ww+wu-wv)&1){ puts("none"); return; }
59     uu=(ww+wu-wv)>>1;
60     write(tu?(wu-uu):(uu-wu)); putchar('\n');
61 }
62 signed main(){
63     n=read(); q=read();
64     for(int i=2;i<=n;i++){
65         int tmp=read(); add(i,tmp); 
66         w[i]=read();
67     } dfs(0,1,0);
68     while(q--){
69         op=read();
70         if(op==1) u=read(), v=read(), ww=read(), calc(u,v,ww);
71         else{ 
72             u=read(); int tmp=w[u]; w[u]=read();
73             c[typ[u]].insert(w[u]-tmp,dfn[u]);
74             c[typ[u]].insert(tmp-w[u],dfn[u]+siz[u]);
75             c[typ[u]^1].insert(tmp-w[u],dfn[u]);
76             c[typ[u]^1].insert(w[u]-tmp,dfn[u]+siz[u]);
77         }
78     }
79     return 0;
80 }
T2

 

T3 Rectangle


好像能扫描线做?但不会。

首先考虑坐标不重的情况。枚举矩形右边界$i$,再向左枚举左边界$j$,然后考虑左右边界中的点。

记矩形至少的上界为$y_x$,至多的下界为$y_n$,那么这四个边界对答案的贡献:

$(i-j)\times \sum_{p<y_n} \sum_{q>y_x}(y_x-y_n)$

记录大于$y_x$和小于$y_n$的点的个数与总和,两两相乘再相减即可。

考虑可重的情况。这时因为左右边界有很多点,同一矩形就可能被重复计算。利用这些点把大矩形分为若干个小矩形分别计算即可。

友校大佬简洁易懂的讲解

$code:$

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 #define pb push_back
 4 using namespace std;
 5 const int NN=1e4+5,p=1e9+7;
 6 int n,ans;
 7 bool vis[2501][2501];
 8 vector<int>sub[2501];
 9 inline int read(){
10     int x=0,f=1; char ch=getchar();
11     while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
12     while(ch<='9'&&ch>='0'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
13     return x*f;
14 }
15 inline void write(int x){
16     char ch[20]; int len=0;
17     if(x<0) x=~x+1, putchar('-');
18     do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x);
19     for(int i=len-1;i>=0;--i) putchar(ch[i]);
20 }
21 struct trearray{
22     int c[2501][2];
23     void insert(int k,int x,int pos){
24         while(pos<=2500){
25             c[pos][k]+=x;
26             pos+=(pos&(-pos));
27         }
28     }
29     int query(int k,int pos){
30         int res=0;
31         while(pos){
32             res+=c[pos][k];
33             pos-=(pos&(-pos));
34         }
35         return res;
36     }
37 }t[2501];
38 signed main(){
39     n=read();
40     for(int i=1;i<=n;i++){
41         int x=read(),y=read();
42         sub[x].pb(y);
43     }
44     for(int i=1;i<=2500;i++){
45         sort(sub[i].begin(),sub[i].end());
46         sub[i].pb(2501);
47     }
48     for(int i=1;i<=2500;i++){
49         if(sub[i].size()==1) continue;
50         for(int j=0;j<sub[i].size()-1;j++) if(!vis[i][sub[i][j]]){
51             vis[i][sub[i][j]]=1;
52             t[i].insert(0,sub[i][j],sub[i][j]);
53             t[i].insert(1,1,sub[i][j]);
54         }
55         for(int j=i-1;j;j--){
56             if(sub[j].size()==1) continue;
57             for(int k=0;k<sub[j].size()-1;k++) if(!vis[i][sub[j][k]]){
58                 vis[i][sub[j][k]]=1;
59                 t[i].insert(0,sub[j][k],sub[j][k]);
60                 t[i].insert(1,1,sub[j][k]);
61             }
62             int lmt=max(sub[i][0],sub[j][0]),tmp1=0,tmp2=0,flag;
63             while(sub[i][tmp1+1]<=lmt) tmp1++;
64             while(sub[j][tmp2+1]<=lmt) tmp2++;
65             while(tmp1<sub[i].size()-1&&tmp2<sub[j].size()-1){
66                 flag=min(sub[i][tmp1+1],sub[j][tmp2+1]);
67                 (ans+=(i-j)*(t[i].query(0,flag-1)-t[i].query(0,lmt-1))*t[i].query(1,min(sub[i][tmp1],sub[j][tmp2])))%=p;
68                 (ans-=(i-j)*(t[i].query(1,flag-1)-t[i].query(1,lmt-1))*t[i].query(0,min(sub[i][tmp1],sub[j][tmp2])))%=p;
69                 (ans+=p)%=p;
70                 lmt=flag;
71                 if(sub[i][tmp1+1]<=lmt) tmp1++;
72                 if(sub[j][tmp2+1]<=lmt) tmp2++;
73             }
74         }
75     }
76     write(ans); putchar('\n');
77     return 0;
78 }
T3

 

posted @ 2021-08-09 16:54  keen_z  阅读(45)  评论(0编辑  收藏  举报