20210820
eriri
先去 \(i\) 比 \(j\) 更加优秀,就需要满足:
即
我们先对所有商店进行这样的排序,然后实际情况就在序列中。
当没有 \(a_i=0\) 的商店时,我们最多去 \(O(log T)\) 个商店,因此可以减少复杂度。
设共有 \(k\) 个 \(a_i > 0\) 的商店,对这 \(k\) 个商店做算法三的 dp,对于每个最终状态\(dp(k, j)\) ,再贪心地按照 \(b_i\) 从小到大的顺序检查还能去几个 \(a_i = 0\) 的商店.
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+5;
struct node{
int a,b;
}a[N];
bool cmp(node x,node y){
return x.a*(y.b+1)>y.a*(x.b+1)||x.a*(y.b+1)==y.a*(x.b+1)&&x.b<y.b;
}
int n,m,T,f[N],b[N],ans;
signed main(){
cin>>n>>T;
for(int i=1;i<=n;i++) scanf("%lld%lld",&a[i].a,a[i].b);
sort(a+1,a+n+1,cmp);
for(int i=1;i<=40;i++) f[i]=T+1;//c
for(int i=1;i<=n;i++){
if(a[i].a) for(int j=40;j>=1;j--) f[j]=min(f[j],(f[j-1]-1)*(a[i].a+1)+a[i].b);
else{
for(int j=i;j<=n;j++) b[j-i+1]=a[i].b;
m=n-i+1;
sort(b+1,b+m+1); break;
}
}
for(int j=0;j<=40;j++)
if(f[j]<=T) {
int res=T-f[j],num=j;
for(int i=1;i<=m;i++){
if(res>=b[i]+1) num++,res-=b[i]+1;
else break;
}
ans=max(ans,num);
} else break;
cout<<ans<<endl;
system("pause");
return 0;
}
yui
一眼容斥,转换成求先手必败的情况。
设 \(p(i) = (2n ? 1)^i\) ,即 \(i\) 堆石子的总方案数。
设 \(f(i)\) 表示 \(i\) 堆石子时先手必败的方案数。
我们考虑让前 \(i ? 1\) 堆石子任意取,通过调整最后一堆石子的数目使得异或和为\(0\) ,方案数为 \(p(i ? 1)\)。
若前 \(i-1\) 堆的之子异或和是0,因为最后一堆不能取到 \(0\) ,所以不合法的方案数为 \(f(i-1)\) 。
若前 \(i-1\) 堆的石子中,有 \(i-2\) 石子异或起来是 \(0\) 那么剩下两堆只能相同个数,方案数为 \((i-1)*(2^n-i+1)*f(i-1)\)
\(O(n)\) 递推即可。
#include<bits/stdc++.h>
using namespace std;
const int N=1e7+10,mod=1e9+7;
int n,f[N],ans,P[N],Pow;
int qmi(int a,int b){
int res=1; while(b){if(b&1) res=1ll*res*a%mod; b>>=1; a=1ll*a*a%mod;} return res;
}
int main(){
cin>>n;
Pow=qmi(2,n);
P[0]=1; f[0]=1;
for(int i=1;i<=n;i++) P[i]=1ll*P[i-1]*(Pow-i)%mod;
for(int i=2;i<=n;i++)
f[i]=(P[i-1]-f[i-1]-1ll*f[i-1]*(i-1)%mod*(Pow-i+1)%mod)%mod;
cout<<(P[n]-f[n])%mod<<endl;
return 0;
}
nanami
左右搜索+状压 \(dp\) 搜索图中的最大团。
具体地,取 \(p = n/2\):
对前 \(p\) 个点,预处理 \(f(S)\) 表示点集 \(S\) 的导出子图的最大团大小。
对后 \(n ? p\) 个点,枚举一个集合 \(T\) , 若点集 \(T\) 的导出子图是团,并且 \(T\) 中所有点邻居的交与前 \(p\) 个点交集为 \(S\) ,就找到了一个大小为 \(|T| + f(S)\) 的团。
时间复杂度为 \(O(2^{n/2}n)\) 。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n, m, x, f[(1 << 20) + 10], pre, ans;
ll g[50];
int main() {
scanf("%d%d%d", &n, &m, &x);
for(int i=1,x,y;i<=m;i++){scanf("%d%d",&x,&y);g[x]|=1ll<<(y-1);g[y]|=1ll<<(x-1);}
pre=min(n,20);
for(int S=1;S<(1<<pre);S++){
for (int i=1;i<=pre;i++)
if(S&(1<<(i-1))) {
int T=g[i]&S;
f[S]=max(f[S],f[T]+1);
}
}
for (ll S=0;S<(1ll<<n);S+=1<<pre) {
bool flag=true;
int T=(1<<pre)-1,num=0;
for (int i=pre+1;i<=n;i++)
if (S&(1ll<<(i-1))){
num++;
if((S&g[i])!=(S-(1ll<<(i-1)))) flag=false;
else T&=g[i];
}
if(flag) ans=max(ans,num+f[T]);
}
printf("%.6lf", (double)x*x*(ans-1)/ans/2);
return 0;
}
ichigo
第二类斯特林数
对于这个式子,我们可以转化成:
我们利用容斥原理,计算第二类斯特林数:
线性筛处理积性函数 \(f(i)=i^n\) 即可满分。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+5,mod=998244353;
int fac[N],suma,sumw,n,k;
int qmi(int a,int b){
int res=1; while(b){if(b&1) res=1ll*res*a%mod; b>>=1; a=1ll*a*a%mod;} return res;
}
int C(int n,int m){return (fac[n]*qmi(fac[m],mod-2)%mod*qmi(fac[n-m],mod-2)%mod);}
int calc(int n,int k){
int sum=0;
for(int i=0;i<=k;i++){
if(i&1) sum=((sum-C(k,i)*qmi(k-i,n))%mod+mod)%mod;
else sum=(sum+C(k,i)*qmi(k-i,n)%mod)%mod;
}
return qmi(fac[k],mod-2)*sum%mod;
}
signed main(){
cin>>n>>k; fac[0]=1;
for(int i=1;i<=n;i++) fac[i]=(fac[i-1]*i)%mod;
suma=(calc(n,k)+calc(n-1,k)*(n-1)%mod)%mod;
for(int i=1,w;i<=n;i++){
scanf("%lld",&w); sumw+=w;
if(sumw>=mod) sumw-=mod;
}
cout<<suma*sumw%mod<<endl;
return 0;
}