多校冲刺 noip 11.06

多校冲刺 noip 11.06

今天我以为我\(AK\)了,结果又挂分了......

关于我每天都想\(AK\)但是做不到这件事。。。

T1 破门而入

裸的第一类斯特林数,我\(TM\)看了一个小时才看出来

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=3005;
const int mod=998244353;
int n,k,dp[N][N],ans;
signed main(){
    freopen("broken.in","r",stdin);
    freopen("broken.out","w",stdout);
    scanf("%lld%lld",&n,&k);
    dp[1][1]=1;
    fo(i,2,n)fo(j,1,min(i,k))dp[i][j]=(dp[i-1][j]*(i-1)+dp[i-1][j-1])%mod;
    fo(i,1,k)ans=(ans+dp[n][i])%mod;
    printf("%lld",ans);
    return 0;
}

T2 翻转游戏

发现反转的区间左右字母相同的可以删去,那么直接扫一遍就好了

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=3e6+5;
int n,buc[30],ans;char s[N];
signed main(){
    freopen("turn.in","r",stdin);
    freopen("turn.out","w",stdout);
    scanf("%s",s+1);n=strlen(s+1);ans=n*(n+1)/2;
    fo(i,1,n)buc[s[i]-'a']++,ans-=buc[s[i]-'a'];
    printf("%lld",ans+1);
    return 0;
}

T3 奶油蛋糕塔

发现不同的蛋糕只有\(10\)个,最多会奇数个相同的可以直接合并

偶数的话就拆出一个最小的,最多\(20\)个,直接状压就行了

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=5e5+5;
int n;
int td[N],tp[N];
int buc[30],num[30],las[30];
int ji[30][3];
int d[30],p[30],cnt;
int dp[1<<20][5],ans;
signed main(){
    freopen("cake.in","r",stdin);
    freopen("cake.out","w",stdout);
    scanf("%d",&n);
    memset(las,0x3f,sizeof(las));
    fo(i,1,n){
        char x[5];
        scanf("%d",&td[i]);
        scanf("%s",x+1);tp[i]|=(1<<(x[1]-'W'));
        scanf("%s",x+1);tp[i]|=(1<<(x[1]-'W'));
        buc[tp[i]]+=td[i];
        num[tp[i]]++;
        las[tp[i]]=min(las[tp[i]],td[i]);
    }
    fo(i,0,(1<<4)-1){
        if(!num[i])continue;
        fo(j,0,3)if((i>>j)&1)ji[i][++ji[i][0]]=j;
        if(!ji[i][2])ji[i][2]=ji[i][1];
        if((num[i]&1)||ji[i][1]==ji[i][2]){
            d[++cnt]=buc[i];
            p[cnt]=i;
        }
        else{
            d[++cnt]=buc[i]-las[i];
            p[cnt]=i;
            d[++cnt]=las[i];
            p[cnt]=i;
        }
    }
    //cout<<"SB"<<endl;
    memset(dp,0x8f,sizeof(dp));
    dp[0][0]=dp[0][1]=dp[0][2]=dp[0][3]=0;
    fo(i,0,(1<<cnt)-1){
        fo(j,0,3){
            if(dp[i][j]<0)continue;
            fo(k,1,cnt){
                if((i>>k-1)&1)continue;
                if(ji[p[k]][1]!=j&&ji[p[k]][2]!=j)continue;
                if(ji[p[k]][1]==j)dp[i|(1<<k-1)][ji[p[k]][2]]=max(dp[i|(1<<k-1)][ji[p[k]][2]],dp[i][j]+d[k]);
                else dp[i|(1<<k-1)][ji[p[k]][1]]=max(dp[i|(1<<k-1)][ji[p[k]][1]],dp[i][j]+d[k]);
            }
            ans=max(ans,dp[i][j]);
        }
    }
    printf("%d",ans);
    return 0;
}

T4 多重影分身之术

话说我推出\(\mathcal{O(n^2)}\)的转移方程之后

发现和前两天做的某一个\(CF\)d的题非常像,于是开始二分答案

于是我\(check\)的时候错掉了,于是与\(AK\)无缘了

于是我考场后一会就改出来了,并且发现我的\(check\)可以\(\mathcal{O(n)}\)解决,就切掉了

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=3e5+5;
const int inf=0x3f3f3f3f;
int n,m,man[N],thg[N];
bool check(int x){
    int it=0;
    fo(i,1,n){
        int now=x,las=it+1;
        if(now<abs(man[i]-thg[las])&&thg[las]<=man[i])return false;
        while(thg[it+1]<man[i])it++;//cout<<it<<endl;
        if(thg[las]>=man[i])while(now>=thg[it+1]-man[i]&&it<m)it++;
        else while((now>=2*(thg[it+1]-man[i])+(man[i]-thg[las])
            ||now>=(thg[it+1]-man[i])+2*(man[i]-thg[las]))&&it<m)it++;
        if(it==m)return true;
    }
    if(it==m)return true;
    else return false;
}
signed main(){
    freopen("duplication.in","r",stdin);
    freopen("duplication.out","w",stdout);
    scanf("%d%d",&n,&m);
    fo(i,1,n)scanf("%d",&man[i]);
    fo(i,1,m)scanf("%d",&thg[i]);
    sort(man+1,man+n+1);
    sort(thg+1,thg+m+1);
    // fo(i,1,n)cout<<man[i]<<" ";cout<<endl;
    // fo(i,1,m)cout<<thg[i]<<" ";cout<<endl;
    int l=0,r=1.1e9,mid;
    while(l<r){
        mid=l+r>>1;
        if(check(mid))r=mid;
        else l=mid+1;
    }
    printf("%d",l);
    return 0;
}
上一篇:多校冲刺 noip 11.07


下一篇:python中的文件操作