CSP 后多校三
A. 莓良心
斯特林数,先鸽了.
B. 尽梨了
很容易就知道要做临项微扰,然后就不会了.
自己以为自己可以选择每次贪心删掉负贡献最大的从而构成最优结果,或者每次向序列中加数从而构成最优劣的.
可是第二种思路由于自己认为空间是 \(O(n^2)\) 直接就被自己否定了,于是绞尽脑汁想第一种思路应该怎么维护.
可是却没有发现值域是指数级的增长,所以可以把空间直接压成 \(O(nlogn)\).
自己的第一种思路想了很久其实应该换的,但是想要换可自己的思路迟迟扯不出来就死了.
以后做题应该更果断一些,每个思路都要思考,不要觉得某一种思路想了想觉得不可行就弃了.
其实这种指数级的值域增长在最近几天就接触过(noip模拟81 偶数),但是自己忘了实在不应该.
于是 \(dp\) 乱写就可以了.
B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
#define ll long long
#define lf double
#define ull unsigned ll
#define pb push_back
#define mp make_pair
#define lb lower_bound
#define ub upper_bound
#define lbt(x) ((x)&(-(x)))
#define Fill(x,y) memset(x,y,sizeof(x))
#define Copy(x,y) memcpy(x,y,sizeof(x))
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
auto read=[]()->ll{
ll w=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
return cit?w:(-w);
};
} using namespace BSS;
const ll N=2e5+21;
ll m,n,cnt,tot,lg2,ans;
struct I { ll a,b; } p[N];
ll B[N],dp[N],pre[N];
auto D=[](ll i,ll j)->lf{ return (1.0*i)/(1.0*j); };
signed main(){
File(eriri);
n=read(),m=read(),lg2=log2(m)+1; ll a,b;
for(ll i=1;i<=n;i++){
a=read(),b=read(),( a ? (p[++cnt].a=a,p[cnt].b=b) : (B[++tot]=b+1) );
}
for(ll i=1;i<=cnt;i++) p[i].b+=p[i].a+1;
sort(B+1,B+1+tot),sort(p+1,p+1+cnt,[](I i,I j){ return D(i.b,i.a)<D(j.b,j.a); });
fill(dp+1,dp+1+100,1e10),dp[0]=0;
for(ll i=1;i<=cnt;i++){
for(ll j=lg2;j>=1;j--){
dp[j]=min(dp[j],dp[j-1]*p[i].a+p[i].b+dp[j-1]);
assert(dp[j-1]*p[i].a+p[i].b>=0);
}
}
Fill(pre,0x3f),pre[0]=0;
for(ll i=1;i<=tot;i++) pre[i]=pre[i-1]+B[i];
for(ll i=lg2,j=0;i>=0;i--){
while(dp[i]+pre[j+1]<=m and j<tot) j++;
// cout<<i<<' '<<dp[i]<<' '<<j<<' '<<pre[j]<<endl;
if(dp[i]+pre[j]<=m) ans=max(ans,i+j);
}
printf("%lld\n",ans),exit(0);
}
C. 团不过
\(dp\),又死了......正难则反,又没想到......
很多方案数的计算,都应该考虑一下正难则反,有时候问题简化一大半.
C_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
#define ll long long
#define lf double
#define ull unsigned ll
#define pb push_back
#define mp make_pair
#define lb lower_bound
#define ub upper_bound
#define lbt(x) ((x)&(-(x)))
#define Fill(x,y) memset(x,y,sizeof(x))
#define Copy(x,y) memcpy(x,y,sizeof(x))
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
auto read=[]()->ll{
ll w=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
return cit?w:(-w);
};
} using namespace BSS;
const ll N=1e7+21,mod=1e9+7;
ll m,n;
ll f[N],g[N];
auto ksm=[](ll a,ll b,ll c,ll w=1)->ll{
for(a%=c,b%=(c-1);b;b>>=1,a=a*a%c) if(b&1) w=w*a%c;
return w%c;
};
signed main(){
File(yui);
n=read(),g[0]=ksm(2,n,mod),g[1]=g[0]-1,f[1]=0,f[2]=0;
for(ll i=2;i<=n;i++) g[i]=(g[0]-i+mod)%mod*g[i-1]%mod;
for(ll i=3;i<=n;i++)
f[i]=(g[i-1]-f[i-1]-(i-1)*(g[0]-i+1+mod)%mod*f[i-2]%mod+mod+mod)%mod;
printf("%lld\n",(g[n]-f[n ]+mod)%mod),exit(0);
}
D. 七负我
基本没咋想,看到是实数就直接否定自己了.
其实并不是很难,看到部分分一个 \(n\le20\),一个 \(n\le40\),按理来说应该是显然的 \(meet\ in\ the\ middle\).
另外推推性质就行了,调整法要学会.
D_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
#define ll long long
#define lf double
#define ull unsigned ll
#define pb push_back
#define mp make_pair
#define lb lower_bound
#define ub upper_bound
#define lbt(x) ((x)&(-(x)))
#define Fill(x,y) memset(x,y,sizeof(x))
#define Copy(x,y) memcpy(x,y,sizeof(x))
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
auto read=[]()->ll{
ll w=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
return cit?w:(-w);
};
} using namespace BSS;
const ll N=500,W=1<<21;
lf z;
ll S,T;
ll m,n,mid,lft,ans1,ans2,ans;
ll num[W],cir[W][2];
ll e[N][2];
signed main(){
File(nanami);
n=read(),m=read(),z=read(); ll u,v,w,res,flag;
mid=(n>>1)|(n&1),lft=n-mid,S=(1<<mid)-1,T=(1<<lft)-1;
for(ll i=1;i<=m;i++){
u=read(),v=read();
v<=mid ? (e[u][0]|=(1<<v-1)) : (e[u][1]|=(1<<v-mid-1)) ;
u<=mid ? (e[v][0]|=(1<<u-1)) : (e[v][1]|=(1<<u-mid-1)) ;
}
for(ll i=1;i<=mid;i++) e[i][0]|=(1<<i-1);
for(ll i=mid+1;i<=n;i++) e[i][1]|=(1<<i-mid-1);
for(ll i=1;i<W;i++) num[i]=num[i&(i-1)]+1;
for(ll i=1;i<=S;i++){
flag=1;
for(ll j=1;j<=mid;j++){
if(!((i>>j-1)&1)) continue;
if((e[j][0]&i)!=i) { flag=0; break; }
}
if(flag) ans=max(ans,num[i]),cir[i][0]=num[i];
for(ll s=i;s and (!cir[i][0]);(--s)&=i){
cir[i][0]=max(cir[i][0],cir[s][0]);
}
}
for(ll i=1;i<=T;i++){
flag=1;
for(ll j=1;j<=lft;j++){
if(!((i>>j-1)&1)) continue;
if((e[j+mid][1]&i)!=i) { flag=0; break; }
}
if(flag) ans=max(ans,num[i]),cir[i][1]=num[i];
for(ll s=i;s and (!cir[i][1]);(--s)&=i){
cir[i][1]=max(cir[i][1],cir[s][1]);
}
}
for(ll i=1;i<=S;i++){
if(cir[i][0]!=num[i]) continue; res=T;
for(ll j=1;j<=mid;j++){
if(!((i>>j-1)&1)) continue;
res&=e[j][1];
}
ans=max(ans,num[i]+cir[res][1]);
}
for(ll i=1;i<=T;i++){
if(cir[i][1]!=num[i]) continue; res=S;
for(ll j=1;j<=lft;j++){
if(!((i>>j-1)&1)) continue;
res&=e[j+mid][0];
}
ans=max(ans,num[i]+cir[res][0]);
}
lf x=ans; x=1.0*z*z*(x-1.0)/(2.0*x);
printf("%.6lf\n",x),exit(0);
}
/*
6 9 1
6 1
5 1
4 4
2 6
4 1
4 2
5 1
6 1
5 2
*/