3.24省选测试
最近有点犯神经...
$T1$
一开始想到了数位$dp$,基本上是对的,但是并不会求贡献了
就是这些位置任选的贡献怎么求,我被这部分卡住了
$f(i)$分为三种情况,分别是$i^0,i^1,i^2$
就是考虑从这这一位开始任选的贡献怎么求
for(int i=1;i<=50;i++) { my_2[i]=my_2[i-1]*2; res0[i]=res0[i-1]*3%mod; //乘三是为什么? //首先比原来多了一位1 //选择0,还是原来的贡献,否则,原来的每种情况都*2 res1[i]=(res1[i-1]*3+res0[i-1]*(my_2[i-1]%mod)%mod)%mod; //一次项也好说,选了,首先我们的m都乘了2,我们这 res2[i]=(res2[i-1]*3+2*res1[i-1]*(my_2[i-1]%mod)%mod+res0[i-1]*(my_2[i-1]%mod)%mod*(my_2[i-1]%mod)%mod)%mod; }
$Sit_1:k=0$
我们这个是求所有的小于一个数的贡献,我们现在推完了$res[i-1]$.第$i-1$位开始任选的所有$f$之和
我们现在要求$res[i]$,显然我们可以把原来的贡献加上,考虑这一位是$1$,那么这时候我们多出来的贡献就是在原来的基础上,都多了一位$1$,这就相当于,前面的贡献$\times 2$
$Sit_2:k=1$
$f(x)=2^{len-1}\times x$
还是加上原来的贡献,我们对于前面那个式子,首先对应转移,我们前面式子乘了二,加上,后面的,对应的每一个$x$,还少一部分$x$,就是把每个$x$都多了$2^{len-1}\times$需要加几次
我发现我就是个推式子的菜鸡中的战斗鸡...
我们考虑这一位
$f(x+2^i)=2^{len}(x+2^i)$
$f(x)=2^{len-1}x$
$f(x+2^i)=f(x)\times 2+2^i\times 2^{len}$
我们现在要求的是原来的所有的$2^{len}$和就是$Sit_1$了
艹.我是不是傻啊...
$Sit_3:k=2$
简单点考虑,我们这个每一个都是一个$x^2$
貌似很难搞,前面不变
$f(x)=\sum_{i=0}^x C(x,i)\mod 2\times i^2$
$f(x+2^i)=\sum_{i=0}^{x+2^i} C(x+2^i,i)\mod 2\times i^2$
其实有值的位置是一样的,真的顿悟...
拆式子,我们多的是什么,$(x+a)^2=x^2+2\times a\times x + a^2$
然后和上一个一样推一下就好了
#include<bits/stdc++.h> #define mod 1000000007 #define int long long #define MAXN 60 using namespace std; int T,k,res0[MAXN],res1[MAXN],res2[MAXN],my_2[MAXN]; struct node { int s0,s1,s2; friend node operator - (node a,node b) { return node{((a.s0-b.s0)%mod+mod)%mod,((a.s1-b.s1)%mod+mod)%mod,((a.s2-b.s2)%mod+mod)%mod}; } friend node operator + (node a,node b) { return node{(a.s0+b.s0)%mod,(a.s1+b.s1)%mod,(a.s2+b.s2)%mod}; } }; node dp(int x,int wei) { while(my_2[wei]>x) { wei--; } //不是很理解,这个东西的计算方式 //我想的是,既要考虑当前数字被那些数字包含,还要考虑这些包含的数字被哪些数字包含 if (my_2[wei]==x) return node{res0[wei],res1[wei],res2[wei]}; node ret1=dp(x-my_2[wei],wei),ret2=node{res0[wei],res1[wei],res2[wei]},ret3; ret3.s0=ret1.s0*2%mod; ret3.s1=(ret1.s1*2%mod+my_2[wei]%mod*ret1.s0%mod)%mod; ret3.s2=(ret1.s2*2%mod+my_2[wei]*2%mod*ret1.s1%mod+my_2[wei]%mod*ret1.s0%mod*(my_2[wei]%mod)%mod)%mod; return ret2+ret3; } void Init() { res0[0]=1; res1[0]=0; res2[0]=0; my_2[0]=1; for(int i=1;i<=50;i++) { my_2[i]=my_2[i-1]*2; res0[i]=res0[i-1]*3%mod; //乘三是为什么? //首先比原来多了一位1 //选择0,还是原来的贡献,否则,原来的每种情况都*2 res1[i]=(res1[i-1]*3+res0[i-1]*(my_2[i-1]%mod)%mod)%mod; //一次项也好说,选了,首先我们的m都乘了2,我们这 res2[i]=(res2[i-1]*3+2*res1[i-1]*(my_2[i-1]%mod)%mod+res0[i-1]*(my_2[i-1]%mod)%mod*(my_2[i-1]%mod)%mod)%mod; } cout<<res1[2]<<" "<<res1[3]<<endl; } signed main() { // freopen("dialog.in","r",stdin); // freopen("dialog.out","w",stdout); Init(); scanf("%lld %lld",&T,&k); for(int i=1,l,r;i<=T;++i) { scanf("%lld%lld",&l,&r); node Ans=dp(r+1,50)-dp(l,50); if(k==0) { printf("%lld\n",Ans.s0); } if(k==1) { printf("%lld\n",Ans.s1); } if(k==2) { printf("%lld\n",Ans.s2); } } return 0; }
$T2$
一开始想了一个错误的贪心,把没访问到的节点按子树排序,每次选最大的
然后光荣的寄了
最简单的贪心推导,我们目前已经选了最大的点的父亲,我们下一步会选最大点,必然
我们每次找一个最大节点.和父亲合并,表示两个会一起选,这样就相当于,你每一步决策是选一堆点了,然后合并完之后得到新的点权之后再次合并就好了,贪心也太神了吧
#include<bits/stdc++.h> #define int long long #define MAXN 100005 using namespace std; vector<int>rd[MAXN]; int n,r,ans,f[MAXN],fa[MAXN],sum[MAXN],size[MAXN]; bool From[MAXN]; struct node { int sum,size,pos; friend bool operator < (node a,node b) { return a.sum*b.size<a.size*b.sum; } }; priority_queue<node>pq; int Find(int x) { if(f[x]==x) return x; return f[x]=Find(f[x]); } void dfs(int x,int f) { fa[x]=f; for(int i=0;i<rd[x].size();++i) { int y=rd[x][i]; if(y!=f) { dfs(y,x); } } } int news() { int pos=pq.top().pos; while(!pq.empty()&&(pos==r||!From[pos]||sum[pos]!=pq.top().sum||size[pos]!=pq.top().size)) { pq.pop(); pos=pq.top().pos; } if(pq.empty()) return 0; return pos; } signed main() { freopen("visit.in","r",stdin); freopen("visit.out","w",stdout); scanf("%lld %lld",&n,&r); for(int i=1;i<=n;++i) { f[i]=i; size[i]=From[i]=1; } for(int i=1;i<=n;++i) scanf("%lld",&sum[i]); for(int i=1,u,v;i<n;++i) { scanf("%lld %lld",&u,&v); rd[u].push_back(v); rd[v].push_back(u); } dfs(r,0); for(int i=1;i<=n;++i) pq.push((node){sum[i],size[i],i}); int pos; //大概明白我贪心错哪了,这里新造出来每个点的权值其实是平均值 //我每次走的是一块,当着一块权值大我才走 while(pos=news()) { pq.pop(); int F=Find(fa[pos]); ans+=size[F]*sum[pos]; size[F]+=size[pos]; sum[F]+=sum[pos]; f[pos]=F; pq.push((node){sum[F],size[F],F}); } ans+=sum[r]; printf("%lld\n",ans); }
$T3$
有点不可做