Loading

Noip模拟15 2021.7.14

T1 夜莺与玫瑰

题目越发的变态起来。。。

这题刚开始看超级像仪仗队,好不容易码完欧拉函数后尝试×2后输出但不对!!

于是选择了跳过。。。。

正解居然是莫比乌斯函数。。。。我也是醉了

预处理完就剩下$O(1)$求解然而我做不到。。

于是打了超级恶心的前缀和$O(n^2)$预处理以及$O(Tn)$求解。

(多亏JYFHYX想到的手摸数组辗转相除超吊好吧)。

竟然还可以定义short数组防止MLE,小马长见识了。

先考虑到柿子:

$\sum_{a=1}^{n-1}\sum_{b-1}^{m-1}[gcd(a,b)==1]((n-a)(m-b)-max(n-2a,0)*max(m-2b,0))$

证明的话考虑原本筛到(a,b)点,

那么对于(1,1)到(a,b)的矩形每一个点以自己的a/b斜率向下划线作出的贡献是$(n-a)(m-b)$

然后向下再拓展出一个相同的矩形,

这个矩形与先前的那个矩形作出的贡献一样,则减去(前提保证斜率唯一特殊性,即gcd为1)

然后把括号拆开,发现一些不变的东西,

提取公因数之后发现可以维护三个前缀和(short开两个,剩下一个开int不会炸)

一个$prime_{i,j}$表示1~j中与i互质的数的个数(单为i那一层的)

一个$gcd_{i,j}$表示gcd为1的个数

一个$sum_{i,j}$表示1~j所有与i互质的数的和(单维护i那一层的)

然后通过化简的柿子算就行.

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 inline int read(){
 4     int x=0,f=1; char ch=getchar();
 5     while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
 6     while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
 7     return x*f;
 8 }
 9 const int NN=4005,p=1073741824;
10 int T;
11 int sum[NN][NN];
12 short gcd[NN][NN],prime[NN][NN];
13 inline void pre(short n){
14     for(short i=1;i<=n;i++){
15         gcd[i][i]=gcd[i][0]=gcd[0][i]=i;
16         for(short j=1;j<i;j++)
17             gcd[i][j]=gcd[j][i]=gcd[j][i%j];
18     }
19     for(short i=1;i<=n;i++){
20         for(short j=1;j<=n;j++){
21             prime[i][j]=prime[i][j-1];
22             sum[i][j]=sum[i][j-1];
23             if(gcd[i][j]==1){
24                 prime[i][j]++;
25                 sum[i][j]+=j;
26             }
27         }
28     }
29 }
30 namespace WSN{
31     inline int main(){
32         pre(4000);
33         // FILE *A=freopen("1.in","r",stdin);
34         T=read();
35         while(T--){
36             short n=read(),m=read();
37             long long ans=0;
38             for(short i=1;i<n;i++){
39                 (ans+=(n-i)*((long long)prime[i][m-1]*m%p-sum[i][m-1]+p))%=p;
40                 if(2*i<n)
41                 ((ans-=(long long)(n-2*i)*(prime[i][m/2]*m%p-2*sum[i][m/2]%p))+=p)%=p;
42             }
43             printf("%lld\n",(ans*2+n+m+p)%p);
44         }
45         return 0;
46     }
47 }
48 signed main(){return WSN::main();}
View Code

T2 影子

此题非常之离谱,不过$n^2$暴力超好打

正解是个并查集。

先跑树链剖分,把权值排序从大到小

遍历节点将其看作一个集合并将其与所有已经vis过的儿子merge出新的集合,

同时考虑六种情况,因为并查集维护了一个最长路,则有维护构成最长路的两个端点

分别考虑两个集合的不同端点连边构成最长(4种),原来的两个集合本身就有一个是新的最长(2种)

暴力枚举情况即可。最后用这个维护好的和遍历到的点权值相乘最小值即为答案。

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 inline int read(){
 5     int x=0,f=1; char ch=getchar();
 6     while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
 7     while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
 8     return x*f;
 9 }
10 const int NN=550000;
11 int T,n;
12 int son[NN],fa[NN],dep[NN],siz[NN],top[NN],dis[NN];
13 struct snow{int val,id;};snow d[NN];
14 inline bool cmp(snow a,snow b){return a.val>b.val;}
15 struct SNOW{int to,val,next;};SNOW e[NN]; int head[NN],rp;
16 struct node{int st,ed,len,fa;};node s[NN];
17 bool vis[NN];
18 inline void add(int x,int y,int z){e[++rp]=(SNOW){y,z,head[x]}; head[x]=rp;}
19 inline void dfs1(int f,int x){
20     dep[x]=dep[f]+1; siz[x]=1; fa[x]=f;
21     for(int i=head[x];i;i=e[i].next){
22         int y=e[i].to;
23         if(y==f) continue;
24         dis[y]=dis[x]+e[i].val;
25         dfs1(x,y);
26         siz[x]+=siz[y];
27         if(siz[son[x]]<siz[y]) son[x]=y;
28     }
29 }
30 inline void dfs2(int x,int t){
31     top[x]=t;
32     if(!son[x]) return; dfs2(son[x],t);
33     for(int i=head[x];i;i=e[i].next){
34         int y=e[i].to;
35         if(y!=fa[x]&&y!=son[x]) dfs2(y,y);
36     }
37 }
38 inline int LCA(int x,int y){
39     while(top[x]!=top[y]){
40         if(dep[top[x]]<dep[top[y]]) swap(x,y);
41         x=fa[top[x]];
42     }if(dep[x]>dep[y]) swap(x,y);
43     return x;
44 }
45 inline int getfa(int x){return s[x].fa==x?x:getfa(s[x].fa);}
46 inline void merge(int x,int y){
47     x=getfa(x),y=getfa(y); s[y].fa=x;
48     //不要直接定义新值,要不然会连不上边,merge后面的操作都是与fx,fy有关的!!!!!!!!!!!!!!!!!!!!!!
49     int stx=s[x].st,sty=s[y].st,edx=s[x].ed,edy=s[y].ed;
50     int dis1=dis[stx]+dis[sty]-2*dis[LCA(stx,sty)];
51     int dis2=dis[stx]+dis[edy]-2*dis[LCA(stx,edy)];
52     int dis3=dis[edx]+dis[sty]-2*dis[LCA(edx,sty)];
53     int dis4=dis[edx]+dis[edy]-2*dis[LCA(edx,edy)];
54     int dis5=s[y].len,dis6=s[x].len;
55     s[x].len=max(dis1,max(dis2,max(dis3,max(dis4,max(dis5,dis6)))));
56     // cout<<s[x].len<<endl;
57     if(s[x].len==dis1){s[x].ed=sty;return;}
58     if(s[x].len==dis2){s[x].ed=edy;return;}
59     if(s[x].len==dis3){s[x].st=sty;return;}
60     if(s[x].len==dis4){s[x].st=edy;return;}
61     if(s[x].len==dis5){s[x].st=sty; s[x].ed=edy;return;}
62 }
63 namespace WSN{
64     inline int main(){
65         // FILE *A=freopen("1.in","r",stdin);
66         // FILE *B=freopen("1.out","w",stdout);
67         T=read();
68         while(T--){
69             n=read();
70             int ans=0;
71             for(int i=1;i<=n;i++){
72                 d[i].val=read();
73                 d[i].id=i; s[i].fa=i;
74             }
75             for(int i=1;i<n;i++){
76                 int u=read(),v=read(),w=read();
77                 add(u,v,w); add(v,u,w);
78             }
79             dfs1(0,1); dfs2(1,1);
80             sort(d+1,d+n+1,cmp);
81             for(int i=1;i<=n;i++){
82                 int nd=d[i].id,vv=d[i].val;
83                 vis[nd]=1; s[nd].st=s[nd].ed=nd;
84                 s[nd].len=0;
85                 for(int j=head[nd];j;j=e[j].next){
86                     int to=e[j].to;
87                     if(vis[to]&&getfa(nd)!=getfa(to)) merge(nd,to);
88                 }
89                 ans=max(ans,vv*s[getfa(nd)].len);
90             }
91             printf("%lld\n",ans);
92             rp=0; for(int i=1;i<=n;i++) head[i]=0,dis[i]=0,son[i]=0,vis[i]=0;
93             memset(s,0,sizeof(s)); memset(d,0,sizeof(d));
94         }
95         return 0;
96     }
97 }
98 signed main(){return WSN::main();}
View Code

T3 玫瑰花精

看这题时给我的时间已经不多了,虽然看出跟hotel那题差不多但是没空阁哪里扣线段树了。

线段树中维护四个量。分别为在区间内最左,最右的花精位置,中间点,花精应放置的最优位置,

剩下的思路清晰,线段树板子一打。就剩下pushdown搁哪里空着啥也不会。。

考虑n种情况,其实先预先画个图,把维护的东西标识清楚情况自然出来了,剩下的代码也好理解。

 1 void pushup(int id){
 2         le[id]=le[lid]?le[lid]:le[rid];
 3         ri[id]=ri[rid]?ri[rid]:ri[lid];
 4         if(!le[lid]){mi[id]=mi[rid];po[id]=po[rid];return;}
 5         if(!le[rid]){mi[id]=mi[lid];po[id]=po[lid];return;}
 6         int cmo=(le[rid]-ri[lid])>>1;
 7         int an=max(cmo,max(mi[lid],mi[rid]));
 8         if(an==mi[lid]){mi[id]=mi[lid]; po[id]=po[lid];return;}
 9         else if(an==cmo){mi[id]=cmo; po[id]=(le[rid]+ri[lid])>>1;return;}
10         else{mi[id]=mi[rid]; po[id]=po[rid];return;}
11     }

纤细的pushdown。。。

$fairy[x]$记录花精x的位置,注意输出时判断的三种情况。如果树是空树直接输出1。

  1 #include<bits/stdc++.h>
  2 #define lid (id<<1)
  3 #define rid (id<<1|1)
  4 using namespace std;
  5 inline int min(int a,int b){return a<b?a:b;}
  6 inline int max(int a,int b){return a>b?a:b;}
  7 inline int read(){
  8     int x=0,f=1; char ch=getchar();
  9     while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
 10     while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
 11     return x*f;
 12 }
 13 const int NN=3000000,inf=0x7fffffff;
 14 int n,m,fairy[NN];
 15 struct SNOWtree{
 16     int ll[NN<<2],rr[NN<<2];
 17     int le[NN<<2],ri[NN<<2],mi[NN<<2],po[NN<<2];
 18     void pushup(int id){
 19         le[id]=le[lid]?le[lid]:le[rid];
 20         ri[id]=ri[rid]?ri[rid]:ri[lid];
 21         if(!le[lid]){mi[id]=mi[rid];po[id]=po[rid];return;}
 22         if(!le[rid]){mi[id]=mi[lid];po[id]=po[lid];return;}
 23         int cmo=(le[rid]-ri[lid])>>1;
 24         int an=max(cmo,max(mi[lid],mi[rid]));
 25         if(an==mi[lid]){mi[id]=mi[lid]; po[id]=po[lid];return;}
 26         else if(an==cmo){mi[id]=cmo; po[id]=(le[rid]+ri[lid])>>1;return;}
 27         else{mi[id]=mi[rid]; po[id]=po[rid];return;}
 28     }
 29     void build(int id,int l,int r){
 30         ll[id]=l; rr[id]=r;
 31         if(l==r) return;
 32         int mid=(l+r)>>1;
 33         build(lid,l,mid); build(rid,mid+1,r);
 34     }
 35     void update(int id,int pos){
 36         if(ll[id]==rr[id]){
 37             le[id]=ri[id]=pos;
 38             mi[id]=po[id]=0;
 39             return;
 40         }
 41         int mid=(ll[id]+rr[id])>>1;
 42         if(pos<=mid) update(lid,pos);
 43         else update(rid,pos);
 44         pushup(id);
 45     }
 46     void dele(int id,int pos){
 47         if(ll[id]==rr[id]){
 48             le[id]=ri[id]=mi[id]=po[id]=0;
 49             return;
 50         }
 51         int mid=(ll[id]+rr[id])>>1;
 52         if(pos<=mid) dele(lid,pos);
 53         else dele(rid,pos);
 54         pushup(id);
 55     }
 56 }tr;
 57 namespace WSN{
 58     inline int main(){
 59         // FILE *A=freopen("1.in","r",stdin);
 60         // FILE *B=freopen("1.out","w",stdout);
 61         n=read();m=read();
 62         tr.build(1,1,n);
 63         for(int i=1;i<=m;i++){
 64             int opt=read(),x=read();
 65             if(opt==1){
 66                 // cout<<tr.le[1]-1<<" "<<tr.mi[1]<<" "<<n-tr.ri[1]<<endl;
 67                 // for(int j=1;j<=n*4;j++) if(tr.ll[j])
 68                 // cout<<tr.ll[j]<<" "<<tr.rr[j]<<" "<<tr.le[j]<<" "<<tr.ri[j]<<" "<<tr.mi[j]<<endl;
 69                 if(!tr.le[1]){
 70                     tr.update(1,1);
 71                     puts("1"); fairy[x]=1;
 72                     continue;
 73                 }
 74                 else{
 75                     int an=max(tr.le[1]-1,max(n-tr.ri[1],tr.mi[1]));
 76                     if(an==tr.le[1]-1){
 77                         puts("1");
 78                         fairy[x]=1;
 79                         tr.update(1,1);
 80                         continue;
 81                     }
 82                     else if(an==tr.mi[1]){
 83                         printf("%d\n",tr.po[1]);
 84                         fairy[x]=tr.po[1];
 85                         tr.update(1,tr.po[1]);
 86                         continue;
 87                     }
 88                     else{
 89                         printf("%d\n",n);
 90                         fairy[x]=n;
 91                         tr.update(1,n);
 92                         continue;
 93                     }
 94                 }
 95             }
 96             if(opt==2){
 97                 tr.dele(1,fairy[x]);
 98                 fairy[x]=0;
 99                 continue;
100             }
101         }
102         return 0;
103     }
104 }
105 signed main(){return WSN::main();}
View Code
posted @ 2021-07-16 16:41  雪域亡魂  阅读(93)  评论(0编辑  收藏  举报