Multi school sprint noip 10.29

Multi school sprint noip 10.29

Am I blind? And then led me to successfully cut off the last question and change my life?

\(JKlover \) the question is still conscience. At least it's for the big example

As for my second kind of Stirling number, I just spent two hours on the first question. This is a serious strategic mistake

This time I saw that each question had a little clue

However, the depth of thinking is deep, and the meaning of the question needs to be constantly transformed

A good set of questions to exercise the ability of thinking and optimizing algorithms

However, there is only explosive search, and there is no violence that can be taken

T1 berry conscience

The idea in my examination room is troublesome. I decide who is the first one, and then enumerate the following schemes

In the process, multiply the number in each set, so as to calculate how many times each number should be added

Finally, multiply the sum of the weights directly

SB_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=2e3+5;
const int mod=998244353;
int ksm(int x,int y){
    int ret=1;
    while(y){
        if(y&1)ret=ret*x%mod;
        x=x*x%mod;y>>=1;
    }return ret;
}
int n,k,dp[N][N],ans;
int w[N],sum;
int jc[N],inv[N];
int C(int x,int y){return jc[x]*inv[y]%mod*inv[x-y]%mod;}
signed main(){
    freopen("ichigo.in","r",stdin);
    freopen("ichigo.out","w",stdout);
    scanf("%lld%lld",&n,&k);
    fo(i,1,n)scanf("%lld",&w[i]),sum=(sum+w[i])%mod;
    jc[0]=1;fo(i,1,n)jc[i]=jc[i-1]*i%mod;
    inv[0]=1;inv[n]=ksm(jc[n],mod-2);
    fu(i,n-1,1)inv[i]=inv[i+1]*(i+1)%mod;
    dp[0][0]=1;
    fo(i,1,n)fo(j,1,min(n,k))dp[i][j]=(dp[i][j]+dp[i-1][j-1]+dp[i-1][j]*j%mod)%mod;
    fo(i,1,n-k+1)ans=(ans+i*C(n-1,i-1)%mod*dp[n-i][k-1])%mod;
    ans=ans*sum%mod;
    printf("%lld",ans);
    return 0;
}

The recurrence (dp) I wrote in the examination room seems to be the recurrence of the second kind of Stirling number

However, if we use the formula written by my examination room mountain, even the inclusion exclusion method of the second kind of Stirling number can not be cut off

The real idea is that if two numbers appear in the same set, their weights will be added

\[\begin{array}{l} \text { ans }=\left(\sum w_{i}\right) \cdot\left\{\begin{array}{l} n \\ k \end{array}\right\}+\sum_{u \neq v}\left(w_{u}+w_{v}\right) \cdot\left\{\begin{array}{c} n-1 \\ k \end{array}\right\} \\ \text { ans }=\left(\sum w_{i}\right) \cdot\left(\left\{\begin{array}{l} n \\ k \end{array}\right\}+(n-1)\left\{\begin{array}{c} n-1 \\ k \end{array}\right\}\right) \end{array} \]

In this way, it is solved with two Stirling numbers, which can be obtained in the time of \ (\ mathcal{O(nlogn)} \) and \ (\ mathcal{O(n)} \)

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=1e6+5;
const int mod=998244353;
int ksm(int x,int y){
    int ret=1;
    while(y){
        if(y&1)ret=ret*x%mod;
        x=x*x%mod;y>>=1;
    }return ret;
}
int n,k,ans,res1,res2;
int p[N],cnt,pw[N];
bool vis[N];
int w[N],sum,mi[N];
int jc[N],inv[N];
int C(int x,int y){return jc[x]*inv[y]%mod*inv[x-y]%mod;}
signed main(){
    freopen("ichigo.in","r",stdin);
    freopen("ichigo.out","w",stdout);
    scanf("%lld%lld",&n,&k);
    fo(i,1,n)scanf("%lld",&w[i]),sum=(sum+w[i])%mod;
    jc[0]=1;fo(i,1,n)jc[i]=jc[i-1]*i%mod;
    inv[0]=1;inv[n]=ksm(jc[n],mod-2);
    fu(i,n-1,1)inv[i]=inv[i+1]*(i+1)%mod;
    pw[1]=1;fo(i,2,n){
        if(!vis[i])p[++cnt]=i,pw[i]=ksm(i,n-1);
        for(int j=1;j<=cnt&&i*p[j]<=n;j++){
            pw[i*p[j]]=pw[i]*pw[p[j]]%mod;
            vis[i*p[j]]=true;
            if(i%p[j]==0)break;
        }
    }
    int bas=1;fo(i,0,k){res2=(res2+C(k,i)*pw[k-i]%mod*bas+mod)%mod;bas=-bas;}res2=res2*inv[k]%mod;
    bas=1;fo(i,0,k){res1=(res1+C(k,i)*pw[k-i]%mod*(k-i)%mod*bas+mod)%mod;bas=-bas;}res1=res1*inv[k]%mod;
    ans=(res1+(n-1)*res2)%mod;
    ans=ans*sum%mod;
    printf("%lld",ans);
    return 0;
}

I've run out of pears

Seriously, I don't have any ideas on this question in the examination room

Although I think of the sorting method, I can't get through one of the data after I arrange it and look from front to back

Then my mind broke and I went straight to die, okay

Later, after the test, I found that the sorting method was right, but I couldn't choose along

This ranking just tells you that I have selected the store collection in this order

Next, you can \ (DP \). Let \ (dp_{i,j} \) represent the minimum time for the first \ (I \) stores to go to \ (j \)

Just transfer directly. It seems that the complexity is not very good

But for one thing, the increase of time is exponential, so the upper bound of \ (j \) is \ (log \)

In this way, the complexity reaches the \ (log \) level, but you find that the exponential level is for the case where \ (a \) is not equal to \ (0 \)

So the last \ (0 \) is sorted from large to small according to \ (b \), and you can add as much as you can

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=2e5+5;
const int inf=0x3f3f3f3f3f3f3f3f;
int n,T;
struct node {
    int a,b;
    node(){}
    bool operator < (node x)const{
        return x.a*(b+1)<a*(x.b+1);
    }
}sca[N];
int ans,now=1;
int f[N][35];
bool com(node x,node y){return x.b<y.b;}
signed main(){
    freopen("eriri.in","r",stdin);
    freopen("eriri.out","w",stdout);
    scanf("%lld%lld",&n,&T);
    fo(i,1,n)scanf("%lld%lld",&sca[i].a,&sca[i].b);
    sort(sca+1,sca+n+1);
    memset(f,0x3f,sizeof(f));
    int pos=n+1;
    fo(i,0,n)f[i][0]=0;
    fo(i,1,n){
        if(!sca[i].a){pos=i;break;}
        fo(j,1,min(i,30ll))f[i][j]=f[i-1][j];
        fo(j,1,min(i,30ll)){
            if(f[i-1][j-1]==inf)continue;
            if(f[i-1][j-1]+1+(f[i-1][j-1]+1)*sca[i].a+sca[i].b<=T)
                f[i][j]=min(f[i][j],f[i-1][j-1]+1+(f[i-1][j-1]+1)*sca[i].a+sca[i].b);
        }
    }
    fo(i,0,min(pos-1,30ll))if(f[pos-1][i]<=T)ans=max(ans,i);
    int sum=0;
    sort(sca+pos,sca+n+1,com);
    fo(i,pos,n){
        sum+=sca[i].b+1;
        fo(j,1,min(pos-1,30ll)){
            if(sum+f[pos-1][j]<=T)ans=max(ans,j+i-pos+1);//cout<<j<<" "<<i<<" "<<pos<<" "<<j+i-pos+1<<endl;
        }
    }
    printf("%lld",ans);
}

T3 regiment, but

Only \ (10min \) is left when looking at this question

Then I searched and left. In fact, this question has been very kind

It can be solved by recursion, which is not as difficult as we think

Please look at the solution... I'm cooing

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=1e7+5;
const int mod=1e9+7;
int ksm(int x,int y){
    int ret=1;
    while(y){
        if(y&1)ret=ret*x%mod;
        x=x*x%mod;y>>=1;
    }return ret;
}
int n,ans;
int pw[N],p[N];
int f[N];
signed main(){
    freopen("yui.in","r",stdin);
    freopen("yui.out","w",stdout);
    scanf("%lld",&n);
    pw[0]=1;fo(i,1,n)pw[i]=pw[i-1]*2%mod;
    p[0]=1;fo(i,1,n)p[i]=p[i-1]*((pw[n]-i+mod)%mod)%mod;
    f[1]=f[2]=0;
    fo(i,3,n)f[i]=(p[i-1]-f[i-1]-(i-1)*(pw[n]-i+1)%mod*f[i-2]%mod+mod+mod)%mod;
    printf("%lld",(p[n]-f[n]+mod)%mod);
    return 0;
}

T4 seven negative me

This time I can cut off this question in the examination room, which completely depends on my hand. I took this as the second question

Then think it's very simple and very confident \ (meet\ in\ the\ middle \)

The conclusion is that complete graphs contribute the most

So we just need to find the largest complete subgraph in this graph

First find the first half, then find the second half, and merge directly!!!!!

AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=41;
int n,m,l,r,ul,ur;
int e[N][2],mx;
int sum[1<<20],ys[1<<20],rit[1<<20];
bool vis[1<<20];
double x,ans;
signed main(){
    freopen("nanami.in","r",stdin);
    freopen("nanami.out","w",stdout);
    scanf("%d%d%lf",&n,&m,&x);
    l=n>>1;ul=(1<<l)-1;
    r=n-l;ur=(1<<r)-1;
    fo(i,1,m){
        int x,y;
        scanf("%d%d",&x,&y);
        if(y>l)e[x][1]|=(1<<y-l-1);
        else e[x][0]|=(1<<y-1);
        if(x>l)e[y][1]|=(1<<x-l-1);
        else e[y][0]|=(1<<x-1);
    }
    fo(i,1,l)e[i][0]|=(1<<i-1);
    fo(i,1,r)e[i+l][1]|=(1<<i-1);
    fo(i,1,max(ul,ur))sum[i]=sum[i-(i&-i)]+1;
    fo(s,1,ul){
        int now,num=sum[s],rig=ur;
        bool flag=true;
        fo(i,1,l){
            if(!((s>>i-1)&1))continue;
            now=e[i][0]&s;rig&=e[i][1];
            if(sum[now]!=num){flag=false;break;}
        }
        if(flag){
            mx=max(mx,num);
            ys[s]=rig;
        }
    }
    fo(s,1,ur){
        int now,num=sum[s];
        bool flag=true;
        fo(i,1,r){
            if(!((s>>i-1)&1))continue;
            now=e[i+l][1]&s;
            if(sum[now]!=num){flag=false;break;}
        }
        if(flag){
            mx=max(mx,num);
            vis[s]=true;
        }
    }
    memset(rit,-1,sizeof(rit));
    fu(s,ul,1){
        if(!ys[s]||sum[s]+sum[ys[s]]<mx)continue;
        if(rit[ys[s]]!=-1){mx=max(mx,sum[s]+rit[ys[s]]);continue;}
        int now=0;
        for(int t=ys[s];t;t=(t-1)&ys[s]){
            if(vis[t])now=max(now,sum[t]);
        }
        rit[ys[s]]=now;
        mx=max(mx,sum[s]+now);
    }
    ans=1.0*mx*(mx-1)/2.0;
    ans=ans*(1.0/(1.0*mx*mx))*x*x;
    printf("%.6lf",ans);
    return 0;
}

Added by meshi on Fri, 29 Oct 2021 11:13:17 +0300