Loading

Noip模拟75 2021.10.12

T1 如何优雅的送分

他说是送分题,我就刚,没刚出来,想到莫比乌斯容斥后就都没推出来

好吧还是不能被恶心的题目,挑衅的语言打乱做题节奏

于是这一场也就没了。。。。

$F(i)$表示$i$的不同质因子集合大小

$2$的这么多次方显然是在枚举子集

那么改变一下枚举顺序,问题答案可以理解为:

几个不同的质数连乘组成的数在$n$的范围内有多少倍数

考虑枚举这个乘积,可以得到式子

$ans=\sum\limits_{k=1}^{n} \mu ^2(k) \left \lfloor \frac{n}{k} \right \rfloor$

关于使用$\mu ^2$考虑$\mu$的定义式

$\begin{cases}
1 &  n= 1\\
(-1)^k &  n= p_1^{c_1}p_2^{c_2}..,k=\sum c\\
0 &  n \textit{含有平方因子}
\end{cases}$

那么$\mu^2$只会有$0,1$两种取值,$\mu^2(k)=0$当且仅当$k$含有平方因子

所以上式等价于$\sum\limits_{i=0}^{n}2^{F(i)}$

考虑让上式变得可做,不妨重新搞一下

$2^{F(i)}=\sum\limits_{d|n}\mu^2(d)=\sum\limits_{d|n}\sum\limits_{k^2|d}\mu(k)$

证明一下正确性,当$d$没有平方因子时显然正确,$k$只能等于$1$

当$d$有平方因子时,考虑为什么$\sum\limits_{k^2|d}\mu(k)=0$

$k$一定可以质因数分解,而当$k$也含有平方因子的情况不考虑,因为他不会对答案造成贡献

那么我们可以把$k$看成多个$1$次质数乘积,考虑从$d$中的含平方因子项中选择

那么$\sum\limits_{k^2|d}\mu(k)=\sum\limits_{i=0}^{n}(-1)^{i}C_{n}^{i}1^{n-i}=(1-1)^n=[n=0]$其中$n$表示$d$的平方因子个数

显然$n!=0$,则当$d$含有平方因子时,$\sum\limits_{k^2|d}\mu(k)=0$

那么

$\sum\limits_{i=0}^n2^{F(i)}=\sum\limits_{i=0}^n\sum\limits_{d|i}\sum\limits_{k^2|d}\mu(k)=\sum\limits_{k=0}^n\mu(k)\sum\limits_{k^2|d}\lfloor\frac{n}{d}\rfloor$

然后改变枚举$k$的几倍

$\sum\limits_{k=0}^n\mu(k)\sum\limits_{k^2|d}\lfloor\frac{n}{d}\rfloor=\sum\limits_{k=0}\mu(k)\sum\limits_{i=1}^{\lfloor\frac{n}{k^2}\rfloor}\lfloor\frac{n}{ik^2}\rfloor$

然后就可以数论分块简单过掉了,(我觉得这题可以单独写一篇题解了,然后美其名曰送分。。)

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 namespace AE86{
 5     inline int read(){
 6         int x=0,f=1;char ch=getchar();
 7         while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 8         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
 9     }inline void write(int x,char opt='\n'){
10         char ch[20];int len=0;if(x<0)x=~x+1,putchar('-');
11         do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
12         for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);}
13 }using namespace AE86;
14 const int NN=1e6+5,mod=1e9+7;
15 int prime[NN],cnt,n,ans,mu[NN],Smu[NN],sum[NN];
16 bool vis[NN];
17 inline void getprime(){
18     mu[1]=1; Smu[1]=1;
19     for(int i=2;i<NN;i++){
20         if(!vis[i]) prime[++cnt]=i,mu[i]=-1;
21         for(int j=1;j<=cnt&&i*prime[j]<NN;j++){
22             vis[i*prime[j]]=1;
23             if(i%prime[j]==0) break;
24             mu[i*prime[j]]=-mu[i];
25         }
26     }
27     for(int i=2;i<NN;i++) Smu[i]=Smu[i-1]+mu[i];
28     
29 }
30 inline int calc(int n){
31     int l=1,r,ans=0;
32     while(l<=n){
33         r=min(n,n/(n/l));
34         (ans+=(n/l)*(r-l+1)%mod)%=mod;
35         l=r+1;
36     }
37     return ans;
38 }
39 namespace WSN{
40     inline short main(){
41         freopen("elegant.in","r",stdin);
42         freopen("elegant.out","w",stdout);
43         getprime();n=read();
44         int l=1,r,ans=0,B=sqrt(n);
45         while(l<=B){
46             r=min(n,n/(n/l));
47             (ans+=calc(n/(l*l))*((Smu[r]-Smu[l-1]+mod)%mod)%mod)%=mod;
48             l=r+1;
49         } write(ans);
50         return 0;
51     }
52 }
53 signed main(){return WSN::main();}
View Code

 

T2 阴阳

数据水直接用$set$水过,后来被卡了,所以现在只有$91$分

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 namespace AE86{
 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();}return x*f;
 8     }inline void write(int x,char opt='\n'){
 9         char ch[20];int len=0;if(x<0)x=~x+1,putchar('-');
10         do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
11         for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);}
12 }using namespace AE86;
13 const int NN=1e5+5;
14 int t,n,opt,x,m,ban,c;
15 set<int> S[NN];
16 struct SNOW{int to,next;}e[NN<<1]; int head[NN],rp;
17 inline void add(int x,int y){
18     e[++rp]=(SNOW){y,head[x]};head[x]=rp;
19     e[++rp]=(SNOW){x,head[y]};head[y]=rp;
20 }
21 namespace tree_division{
22     int dfn[NN],rk[NN],son[NN],fa[NN],top[NN],dep[NN],siz[NN],cnt;
23     inline void dfs1(int f,int x){
24         dep[x]=dep[f]+1; siz[x]=1; fa[x]=f;
25         for(int i=head[x];i;i=e[i].next){
26             int y=e[i].to;if(y==f) continue;
27             dfs1(x,y); siz[x]+=siz[y];
28             if(siz[son[x]]<siz[y]) son[x]=y;
29         }
30     }
31     inline void dfs2(int x,int t){
32         top[x]=t; dfn[x]=++cnt; rk[cnt]=x;
33         if(son[x]) dfs2(son[x],t);
34         for(int i=head[x];i;i=e[i].next){
35             int y=e[i].to;
36             if(y!=fa[x]&&y!=son[x]) dfs2(y,y);
37         }
38     }
39     inline int LCA(int x,int y){
40         while(top[x]!=top[y]){
41             if(dep[top[x]]<dep[top[y]]) swap(x,y);
42             x=fa[top[x]];
43         }if(dfn[x]>dfn[y]) swap(x,y);
44         return x;
45     }
46 }using namespace tree_division;
47 namespace WSN{
48     inline short main(){
49         freopen("yygq.in","r",stdin);
50         freopen("yygq.out","w",stdout);
51         t=read(); n=read();
52         for(int i=1,u,v;i<n;i++) u=read(),v=read(),add(u,v);
53         dfs1(0,1); dfs2(1,1);
54         m=read();int lastans=0;
55         while(m--){
56             opt=read(),x=(read()^(lastans*t));
57             if(opt==1){
58                 ++ban; S[ban]=S[c];
59                 if(x>n){lastans=1000000000,puts("1000000000");continue;}
60                 if(S[ban].find(x)==S[ban].end()) S[ban].insert(x);
61                 else S[ban].erase(S[ban].find(x));
62                 c=ban;
63             }
64             if(opt==2){
65                 if(x>n){lastans=1000000000,puts("1000000000");continue;}
66                 int ans=1000000000;
67                 for(set<int>::iterator it=S[c].begin();it!=S[c].end();it++){
68                     int lca=LCA(*it,x);
69                     ans=min(ans,dep[x]+dep[*it]-dep[lca]*2);
70                 } write(ans); lastans=ans;
71             }
72             if(opt==3){
73                 if(x>ban)continue;
74                 c=x;
75             }
76         }
77         return 0;
78     }
79 }
80 signed main(){return WSN::main();}
View Code

 

T3 你猜是不是找规律

显然不是找规律

$dp$非常好写,重要是优化,他可以用拉格朗日插值(?)

确实一片大雾,真就啥都能优化$dp$

关于多项式的证明现在大佬们貌似还在问,总之题解说啥我干啥就过了

 

 

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 namespace AE86{
 5     inline int read(){
 6         int x=0,f=1;char ch=getchar();
 7         while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 8         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
 9     }inline void write(int x,char opt='\n'){
10         char ch[20];int len=0;if(x<0)x=~x+1,putchar('-');
11         do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
12         for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);}
13 }using namespace AE86;
14 const int NN=3005,mod=1e9+7;
15 int n,k,ans,f[NN];
16 struct node{int x,y;}p[NN<<1];
17 inline int qmo(int a,int b,int ans=1){int c=mod;
18     for(;b;b>>=1,a=a*a%c)if(b&1)ans=ans*a%c;
19     return ans;
20 }
21 inline int inv(int x){return qmo(x,mod-2);}
22 inline int lagrange(int k,int n,int ans=0){
23     for(int i=1;i<=n;i++){
24         int s1=p[i].y%mod,s2=1;
25         for(int j=1;j<=n;j++)
26             if(i!=j) s1=s1*((k-p[j].x+mod)%mod)%mod,s2=s2*((p[i].x-p[j].x+mod)%mod)%mod;
27         ans=(ans+s1*inv(s2)%mod)%mod;
28     }
29     return ans;
30 }
31 namespace WSN{
32     inline short main(){
33         freopen("guess.in","r",stdin);
34         freopen("guess.out","w",stdout);
35         n=read();k=read();f[0]=1;
36         if(!k) return puts("1"),0;
37         p[1].x=1;for(int i=0;i<=k;i++) p[1].y+=f[i];
38         for(int i=2;i<=2*k+1;i++){
39             for(int j=k;j;j--) f[j]=(f[j]+f[j-1]*(i-1)%mod)%mod;
40             for(int j=0;j<=k;j++) (p[i].y+=f[j])%=mod;
41             p[i].x=i;
42         }
43         write(lagrange(n,2*k+1));
44         return 0;
45     }
46 }
47 signed main(){return WSN::main();}
View Code

 

T4 小说

唯一一道联赛难度题目

然后用到了倒背包,就是开两个$dp$一个是放进去的,一个是倒出来的,好理解不好写(bushi)

然后就完了

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 namespace AE86{
 5     inline int read(){
 6         int x=0,f=1;char ch=getchar();
 7         while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 8         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
 9     }inline void write(int x,char opt='\n'){
10         char ch[20];int len=0;if(x<0)x=~x+1,putchar('-');
11         do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
12         for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);}
13 }using namespace AE86;
14 const int NN=1005,MM=7e5+5,mod=998244353;
15 int n,v[NN],a,b,sum,dp[MM<<1],pd[MM];
16 namespace WSN{
17     inline short main(){
18         freopen("novel.in","r",stdin);
19         freopen("novel.out","w",stdout);
20         n=read(); dp[0]=1;
21         for(int i=1;i<=n;i++) v[i]=read();
22         for(int i=1;i<=n;i++){
23             sum+=v[i];
24             for(int j=sum;j>=v[i];j--) dp[j]=(dp[j]+dp[j-v[i]])%mod;
25         }
26         sort(v+1,v+n+1);
27         int mx=0;
28         for(int j=1;j<=n;j++){
29             int tmp=0;memset(pd,0,sizeof(pd));pd[0]=1;
30             for(int i=1;i<=sum;i++){
31                 if(i<v[j]) pd[i]=dp[i];
32                 else pd[i]=(dp[i]-pd[i-v[j]]+mod)%mod;
33             }
34             for(int i=1;i<=sum;i++) tmp+=(pd[i]>0);
35             if(tmp>mx) mx=tmp,a=j;
36             // cout<<tmp<<endl;
37         }
38             // cout<<mx<<endl;
39         write(v[a],' '); sum-=v[a];
40         memset(dp,0,sizeof(dp)); dp[sum]=1;
41         for(int i=1;i<=n;i++) if(i!=a){
42             for(int j=sum*2;j>=v[i];j--)
43                 if(dp[j-v[i]]) dp[j]=1;
44             for(int j=0;j<=sum*2-v[i];j++)
45                 if(dp[j+v[i]]) dp[j]=1;
46         }
47         for(int i=1;i<=sum;i++)
48             if(!dp[i+sum]) return write(i),0;
49         write(sum+1);
50         return 0;
51     }
52 }
53 signed main(){return WSN::main();}
View Code

 

posted @ 2021-10-16 08:25  雪域亡魂  阅读(84)  评论(0编辑  收藏  举报