# Mock 85 exam summary

Keywords: dp

Title Background praise

### Pass the exam

Or is there a problem with the opening sequence
It's not easy to visually check T1. T2 is greedy, so he plunged into T3 and began to push persimmons. As a result, there was no fruit for 1.5h, and then the mentality collapsed
Then they began to fight violence. T2 made a mess that has been sorted all the time. I don't know how many points there are. T1 saw that it was sterling, and there were 40. T4 took the sub task and ran away
I didn't know what to do for half an hour and oj didn't have to check the documents, so I pushed for a long time and didn't push anything out
40 + 35 + 20 + 20 = 125, higher than expected, although it is still nothing

### T1. Conscience

What the examination room wants is to enumerate the size of each person's group

$ans=\sum_{w_i}\times (\sum_{i=0}^{n-k}(i+1)\dbinom{n-1}{i}{n-i-1 \brace k-1})$

Then he found out that it wouldn't count as a listerin and died
The positive solution is a different method. It means that for all elements in a group, each pair will produce \ (w_x+w_y \) contribution, which is

The second is to separate one from two. This persimmon will find that only one Stirling is used in the whole process
So it's obtained from sterling's formula

${n \brace k}=\frac{1}{k!}\sum_{i=0}^k (-1)^i\dbinom{k}{i}(k-i)^n$

So you can do it directly. The formula master has told you in his lecture. Recite it first

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353;
const int N=2050;
int sit[N][N],jc[N],n,k,a[N],inv[N],jcny[N];
inline int C(int x,int y)
{
if(x<y)return 0;
if(!y)return 1;
return jc[x]*jcny[y]%mod*jcny[x-y]%mod;
}
signed main()
{
freopen("ichigo.in","r",stdin);
freopen("ichigo.out","w",stdout);
sit[0][0]=jc[0]=1;
for(int i=1;i<=2000;i++)
{
sit[i][0]=0;
for(int j=1;j<=i;j++)
sit[i][j]=(sit[i-1][j-1]+j*sit[i-1][j]%mod)%mod;
jc[i]=jc[i-1]*i%mod;
}
jc[1]=jcny[1]=jcny[0]=inv[1]=1;
for(int i=2;i<=2000;i++)
{
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
jcny[i]=jcny[i-1]*inv[i]%mod;
}
cin>>n>>k;int ans=0,sum=0;
for(int i=1;i<=n;i++)scanf("%lld",&a[i]),sum=(sum+a[i])%mod;
for(int i=0;i<=n-k;i++)ans=(ans+(i+1)*C(n-1,i)%mod*sit[n-1-i][k-1]%mod)%mod;
ans=ans*sum%mod;cout<<ans<<endl;
return 0;
}


### T2. All pears are gone

It is found that it should be sorted according to \ (a/b \), so that one of its subsequences must be finally selected. More accurately, \ (I \) meets \ ((b_i + 1) a_j < (b_j + 1) a_i \) before \ (J \)
This east can obviously be dp, \ (f_{i,j} \) represents the minimum cost of the first \ (I \) to buy \ (j \). It is found that when \ (a > 0 \) his cost index increases, the second dimension only opens \ (log \)
Finally, there is a pile of \ (a=0 \), which can be scanned to judge how much more to buy. The total complexity \ (n\log n \)

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=200030;
struct t{int a,b;}p[N];
inline bool cmp(t x,t y)
{
if((x.b+1)*y.a!=(y.b+1)*x.a)return (x.b+1)*y.a<(y.b+1)*x.a;
return x.b<y.b;
}
int f[N][35];
signed main()
{
freopen("eriri.in","r",stdin);
freopen("eriri.out","w",stdout);
int n,T;cin>>n>>T;
for(int i=1;i<=n;i++)scanf("%lld%lld",&p[i].a,&p[i].b);
sort(p+1,p+1+n,cmp);int ga=n+1;
for(int i=1;i<=n;i++)if(!p[i].a){ga=i;break;}
memset(f,0x3f,sizeof(f));
f[0][0]=0;
for(int i=1;i<ga;i++)
{
for(int j=0;j<=min(i,(int)30);j++)
{
if(f[i-1][j]<=T)f[i][j]=min(f[i][j],f[i-1][j]);
if(f[i-1][j-1]<=T&&j)f[i][j]=min(f[i][j],f[i-1][j-1]+1+(f[i-1][j-1]+1)*p[i].a+p[i].b);
}
}
int ans=0;
for(int i=0;i<=30;i++)
{
if(f[ga-1][i]>T)break;int s=i,sum=f[ga-1][i];
for(int j=ga;j<=n;j++)
{
sum+=p[j].b+1;
if(sum>T)break;s++;
}
ans=max(ans,s);
}
cout<<ans<<endl;
return 0;
}


### T3. Mission

The idea of Canon's weakened version is basically the same. Let \ (f_i \) represent the number of schemes that must be defeated by the first hand in the heap and \ (p_i \) represent the total number of schemes in the heap
The explanation of the title was clear, so it was copied directly

The key is to be able to see that this is a canon, otherwise it will be useless

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1e9+7;
const int N=1e7+10;
int p[N],f[N],n;
inline int ksm(int x,int y)
{
int s=1;x%=mod;
for(;y;y>>=1)
{
if(y&1)s=s*x%mod;
x=x*x%mod;
}
return s;
}
signed main()
{
freopen("yui.in","r",stdin);
freopen("yui.out","w",stdout);
cin>>n;int ga=ksm(2,n);
p[0]=1;for(int i=1;i<=n;i++)p[i]=p[i-1]*(ga-i)%mod;
f[1]=f[2]=0;
for(int i=3;i<=n;i++)f[i]=(p[i-1]-f[i-1]+mod-(ga-i+1+mod)%mod*(i-1)%mod*f[i-2]%mod+mod)%mod;
cout<<(p[n]-f[n]+mod)%mod<<endl;
return 0;
}


### T4. Seven negative me

If there is no edge between two points, a score of 0 must not be inferior when their assigned weight and are determined
Then find the largest clique in the graph, and then distribute the weights equally
You can press it in half, preprocess the largest clique of all subsets in the first half, enumerate the last half of the clique (check it to be a clique), and see the intersection of its outgoing edge and the previous general \ (s \), then the number of points of the current clique \ (i \) plus \ (f_s \) is the answer, and then take the largest one. The implementation is relatively simple

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=2000;
struct node{
int from,to,next;
}a[2*N];
{
a[mm].from=x;a[mm].to=y;
}
int n,m,sum;
inline int getsum(int x)
{
int s=0;
while(x)
{
if(x&1)s++;
x>>=1;
}
return s;
}
vector <int> sta[22];
int f[1ll<<22],to[45],t,tt,v[45][45];
inline bool check(int s)
{
for(int i=1;i<=tt;i++)
{
if(!((s>>(i-1))&1))continue;
int x=i+t;
for(int j=1;j<=tt;j++)
{
if(!((s>>(j-1))&1))continue;
if(j==i)continue;
if(!v[i+t][j+t])return 0;
}
}
return 1;
}
signed main()
{
freopen("nanami.in","r",stdin);
freopen("nanami.out","w",stdout);
cin>>n>>m>>sum;t=n/2;
for(int i=1;i<=m;i++)
{
int x,y;scanf("%lld%lld",&x,&y);
if(x<=t)to[y]|=1ll<<(x-1);
if(y<=t)to[x]|=1ll<<(y-1);
v[x][y]=v[y][x]=1;
}
for(int i=1;i<(1ll<<t);i++)sta[getsum(i)].push_back(i);
for(int i=1;i<=t;i++)f[1ll<<(i-1)]=1;
for(int i=1;i<=t;i++)
{
for(int j=0;j<sta[i].size();j++)
{
int s=sta[i][j];
for(int k=1;k<=t;k++)
{
if((s>>(k-1))&1)continue;
if((to[k]&s)==s&&f[s]==i)f[s|(1ll<<(k-1))]=max(f[s|(1ll<<(k-1))],f[s]+1);
else f[s|(1ll<<(k-1))]=max(f[s|(1ll<<(k-1))],f[s]);
}
}
}
int ans=0;tt=n-t;
for(int i=1;i<(1ll<<t);i++)ans=max(ans,f[i]);
for(int i=1;i<(1ll<<tt);i++)
{
if(!check(i))continue;
int s=(1ll<<t)-1;
for(int j=1;j<=tt;j++)
{
if((i>>(j-1))&1)s&=to[j+t];
}
ans=max(ans,getsum(i)+f[s]);
}
printf("%.6lf\n",1.0*ans*(ans-1)*sum*sum/(2.0*ans*ans));
return 0;
}


### Examination summary

I feel trapped in such a strange circle recently:

Think about the problem, think about it for a long time, and then leave it