Loading

Noip模拟42 2021.8.17

T1 卷

一看跟没有上司的舞会一样,直接敲了然后试个自己造的样例对了就跑了。。。

然而把它想简单了,乘积取模,还能比大小吗?????

显然不能

所以直接让对数的加和跟着$dp$直接一起跑,比大小的都用对数就行

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 inline int AE86(){
 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=2e5+5,p=1e9+7;
11 int n,w[NN],dp[NN][2];
12 double lg[NN],l[NN][2];
13 struct SNOW{int fr,to,next;};SNOW e[NN<<1]; int head[NN],rp;
14 inline void add(int x,int y){
15     e[++rp]=(SNOW){x,y,head[x]};head[x]=rp;
16     e[++rp]=(SNOW){y,x,head[y]};head[y]=rp;
17 }
18 inline void dfs(int f,int x){
19     (dp[x][0]*=w[x])%=p; l[x][0]+=lg[x];
20     for(int i=head[x],y;i;i=e[i].next) if((y=e[i].to)!=f){
21         dfs(x,y);
22         (dp[x][1]*=(l[y][1]>l[y][0]?dp[y][1]:dp[y][0]))%=p;
23         (dp[x][0]*=dp[y][1])%=p;
24         l[x][1]+=max(l[y][1],l[y][0]);
25         l[x][0]+=l[y][1];
26     }
27 }
28 namespace WSN{
29     inline short main(){
30         n=AE86();for(int i=1;i<=n;i++) dp[i][0]=dp[i][1]=1;
31         for(int i=1;i<=n;i++) w[i]=AE86(),lg[i]=log(w[i]);
32         for(int i=1;i<n;i++) add(AE86(),AE86());
33 //        for(int i=1;i<=rp;i++) cout<<e[i].fr<<" "<<e[i].to<<endl;
34         dfs(0,1);
35         printf("%lld\n",l[1][0]>l[1][1]?dp[1][0]:dp[1][1]);
36         return 0;
37     }
38 }
39 signed main(){return WSN::main();}
View Code

 

T2 简单题

组合数学。。。。。不会,永远不会。。。。。。

发现每个偶数都可以拆成一个奇数乘$2^k$得到

不妨把能用那个奇数得到的偶数都划分给那个奇数

如果一个集合选择了这个奇数,那么这个集合相应的选择$x*2^0,x*2^2,x*2^4,x*2^6...$

另外的集合选择剩下的$x*2^1,x*2^3...$,我们分别叫这两种选择的个数为一个数$x$的偶数权和奇数权

这样我们会发现,有时候左右选择不同,两个集合会有一定的数量上的差值,即有时$偶数权-奇数权=1$

因为这个数可能只有偶数个偶数和他构成关系,这样每次进行分配,两个集合都会有相差$1$

那么,我们假设把所有偶数权的放到一个集合,那么算出他集合内元素个数$sum$,

再相应的算出偶数权比奇数权多$1$的奇数个数$Y$,奇数偶数权相等的个数$X$

那么答案可以表示为$2^X*C_{Y}^{sum-m}$

自认为计算这几个量的过程不太好说,也比较喵,所以直接看码吧。

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 inline int AE86(){
 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=10000020,p=10000019;
11 int n,q,h[NN],v[NN],sum,num[100],X,Y;
12 inline int qmo(int a,int b){
13     int ans=1,c=p; a%=c;
14     while(b){
15         if(b&1) ans=(ans*a)%c;
16         b>>=1; a=(a*a)%c;
17     }return ans;
18 }
19 inline void pre(){
20     h[0]=h[1]=1; v[0]=v[1]=1;
21     for(int i=2;i<=10000018;i++) h[i]=h[i-1]*i%p;
22     v[10000018]=qmo(h[10000018],p-2);
23     for(int i=10000017;i>=2;i--) v[i]=v[i+1]*(i+1)%p;
24 }
25 inline int C(int n,int m){
26     if(n<0||m<0||n<m) return 0;
27     return h[n]*v[n-m]%p*v[m]%p;
28 }
29 inline int lucas(int n,int m){
30     if(!m) return 1;
31     return lucas(n/p,m/p)*C(n%p,m%p)%p;
32 }
33 namespace WSN{
34     inline short main(){
35         n=AE86(); q=AE86(); pre();
36         int cnt=0;
37         while(pow(2ll,cnt)<n){
38             int mi=pow(2ll,cnt),f=n/mi;
39             num[cnt]=(f+1)/2; ++cnt;
40         }--cnt;
41         for(int i=2;i<=cnt;i+=2) sum+=num[i];
42         for(int i=0;i<=cnt;i++) num[i]-=num[i+1];
43         for(int i=0;i<=cnt;i++)
44             if(i&1) X+=num[i];
45             else Y+=num[i];
46         sum+=(1+n)>>1;
47         int aa=qmo(2,X);
48         while(q--) printf("%lld\n",aa*lucas(Y,sum-AE86())%p);
49         return 0;
50     }
51 }
52 signed main(){return WSN::main();}
View Code

 

T3 粉丝

求划分数,先科普两种$dp$

$f_{i,j}$表示$dp$到$i$,总和为$j$的划分数,则可以按照完全背包$dp$,每次枚举$i$选择了几个即可

$g_{i,j}$表示划分了$i$个数,总和为$j$的划分数,这是经典的划分数$dp$,有$g_{i,j}=g_{i-1,j}+g_{i,j-i}$

然后发现可以之考虑下界,最后按照前缀和的处理方式算答案就行

$dp$分成两部分,前$\sqrt n$用$f_{i,j}dp$,后面的用$g_{i,j}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(int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);}
13 }using namespace AE86;
14 
15 const int NN=3e5+1;
16 int x,y,n,p,f[NN],g[NN],s[NN],B;
17 inline int work(int ss){
18     if(ss>n) return 0;
19     int m=max(B,ss); f[0]=g[0]=s[0]=1ll;
20     for(int i=ss;i<m;i++)
21         for(int j=i;j<=n;j++) (f[j]+=f[j-i])%=p;
22     for(int i=1;i<=n/m;i++){
23         int t=i*m;
24         for(int j=i;j+t<=n;j++) (g[j]+=g[j-i])%=p;
25         for(int j=0;j+t<=n;j++) (s[j+t]+=g[j])%=p;
26     }
27     int ans=0;
28     for(int i=0;i<=n;i++) (ans+=f[i]*s[n-i]%p)%=p;
29     memset(f,0,sizeof(f));
30     memset(g,0,sizeof(g));
31     memset(s,0,sizeof(s));
32     return ans;
33 }
34 namespace WSN{
35     inline short main(){
36         x=read();y=read();n=read();p=read(); B=sqrt(n);
37         write((work(x)-work(y+1)+p)%p);
38         return 0;
39     }
40 }
41 signed main(){return WSN::main();}
View Code

 

T4 字符串

刚学会$manacher$,先沽了

 

纯属恶搞,如此优秀的通过率谁不爱呢

posted @ 2021-08-18 06:28  雪域亡魂  阅读(91)  评论(0编辑  收藏  举报