noip模拟54[碰巧]

noip模拟54 solutions

今天好像也还好,波波说这个是人家考过的挺难的题,但是人家有好多切掉的

我们啥也不是,害

T1 选择

这个好像和独立集很像啊,不过根本不是。。。

这个题说白了是个废题,因为这个算法不可以推广到一般情况,比如菊花图

主要是利用一个点的度数不超过10,这个地方可以状压

每一颗子树内都只有一个点可以向上走,因为向上的路径只有一条

所以我们可以记录有那些点可以

对于每一个节点我们统计经过它的路径的贡献,最后全部节点都加起来就行了

一个节点最多有10个儿子,我们可以状压来得到这些儿子最大的贡献

还可以判断一下,去掉某一个儿子之后会不会有影响,如果没有,那这个儿子的可以向上走的儿子,也可以是当前点的

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re int
const int N=1005;
inline int read()
{
	int ss=0; bool cit=1; char ch;
	while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
	while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
	return cit?ss:-ss;
}
int n,m,ans;
int to[N*2],nxt[N*2],head[N],rp;
void add_edg(int x,int y){
    to[++rp]=y;
    nxt[rp]=head[x];
    head[x]=rp;
}
int sca[N][N];
vector<int> fre[N];
int dp[(1<<10)+5];
int ji[15],cnt;
void dfs(int x,int f){
    for(re i=head[x],y;i;i=nxt[i]){
        y=to[i];
        if(y==f)continue;
        dfs(y,x);
    }
    cnt=0;for(re i=head[x];i;i=nxt[i])if(to[i]!=f)ji[++cnt]=to[i];
    memset(dp,0,sizeof(dp));
    for(re i=1;i<=cnt;i++)
        for(re k=0;k<fre[ji[i]].size();k++){
            for(re j=i+1;j<=cnt;j++)
                for(re o=0;o<fre[ji[j]].size();o++)
                    if(sca[fre[ji[i]][k]][fre[ji[j]][o]]){
                        dp[(1<<i-1)|(1<<j-1)]=1;break;
                    }
            if(sca[fre[ji[i]][k]][x])dp[(1<<i-1)]=1;
        }
    int S=(1<<cnt)-1;
    for(re s=1;s<=S;s++)
        for(re t=s;t;t=(t-1)&s)
            dp[s]=max(dp[s],dp[t]+dp[s^t]);
    ans+=dp[S];
    for(re i=1;i<=cnt;i++)
        if(dp[S^(1<<i-1)]==dp[S])
            for(re j=0;j<fre[ji[i]].size();j++)
                fre[x].push_back(fre[ji[i]][j]);
    fre[x].push_back(x);
}
void file(){freopen("select.in","r",stdin);freopen("select.out","w",stdout);}
signed main(){
    file();
    //scanf("%d",&n);
    n=read();
    for(re i=1,x,y;i<n;i++){
        //scanf("%d%d",&x,&y);
        x=read(),y=read(),
        add_edg(x,y),add_edg(y,x);
    }
    //scanf("%d",&m);
    m=read();
    for(re i=1,x,y;i<=m;i++){
        //scanf("%d%d",&x,&y);
        x=read(),y=read(),
        sca[x][y]=1,sca[y][x]=1;
    }
    dfs(1,0);printf("%d",ans);
}

表格

最简单的式子应该都有了,官方题解也讲了

就是讨论六种情况,

不对,官方题解啥都讲了,直接上代码吧,就是拉格郎日插值法

注意边界

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 mod=1e9+7;
inline int ksm(int x,int y){
    int ret=1;x%=mod;
    while(y){
        if(y&1)ret=ret*x%mod;
        x=x*x%mod;y>>=1;
    }
    return ret;
}
inline int XLT(int n,int *x,int *y,int xi)
{	int ans=0;
	for(int i=0,s1=1,s2=1;i<=n;++i){	
        s1=1;s2=1;
        for(int j=0;j<=n;++j)
		if(i!=j)s1=s1*(((xi-x[j])%mod+mod)%mod)%mod,s2=s2*(((x[i]-x[j])%mod+mod)%mod)%mod;
		ans=(ans+y[i]%mod*s1%mod*ksm(s2,mod-2)%mod)%mod;
	}
	return (ans+mod)%mod;
}
int n,m,L,R;
int ggx[10],ggy[10],h1x[10],h1y[10],h2x[10],h2y[10];
// inline int g(int x){return (x%mod-2+mod)%mod*(m%mod-x%mod+mod+1)%mod;}
// inline int f(int x){return (x%mod-2+mod)%mod*(n%mod-x%mod+mod+1)%mod;}
inline int g(int x){return (x-2)%mod*((m-x+1)%mod)%mod;}
inline int f(int x){return (x-2)%mod*((n-x+1)%mod)%mod;}
inline int gg(int x){return XLT(3,ggx,ggy,x);}
inline int h1(int x){return XLT(6,h1x,h1y,x);}
inline int h2(int x){return XLT(3,h2x,h2y,x);}
void get_gg(){
    fo(i,0,3){
        ggx[i]=i+3;ggy[i]=0;
        fo(j,3,i+3)ggy[i]=(ggy[i]+g(j))%mod;
    }return ;
}
void get_h1(){
    fo(i,0,6){
        h1x[i]=i+3;h1y[i]=0;
        fo(j,3,i+3)h1y[i]=(h1y[i]+f(j)*gg(R/2+2-j)%mod)%mod;
    }return ;
}
void get_h2(){
    fo(i,0,3){
        h2x[i]=i+3;h2y[i]=0;
        fo(j,3,i+3)h2y[i]=(h2y[i]+f(j)*gg(m)%mod)%mod;
    }return ;
}
signed main(){
    freopen("table.in","r",stdin);
    freopen("table.out","w",stdout);
    scanf("%lld%lld%lld%lld",&n,&m,&L,&R);
    get_gg();get_h1();get_h2();
    int val=0,var=0;
    if(R/2+2-m-1>=3)var=(h1(min(n,R/2-1))-h1(R/2+2-m-1)+mod+h2(R/2+2-m-1))%mod;
    else if(R/2-1>=3)var=h1(min(n,max(R/2-1,0ll)));
    else var=0;
    if(R/2+2-m-1>=min(n,R/2-1))var=h2(min(n,R/2-1));
    R=L-1;get_gg();get_h1();get_h2();
    if(R/2+2-m-1>=3)val=(h1(min(n,R/2-1))-h1(R/2+2-m-1)+mod+h2(R/2+2-m-1))%mod;
    else if(R/2-1>=3)val=h1(min(n,max(R/2-1,0ll)));
    else val=0;
    if(R/2+2-m-1>=min(n,R/2-1))val=h2(min(n,R/2-1));
    //cout<<var<<" "<<val<<endl;
    printf("%lld",(var-val+mod)%mod*6%mod);
}

黑白

好像是和博弈论有那么点关系,我不会SG函数,所以先沽

啊我会了,直接上代码

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=105;
const int mod=998244353;
int n,a[N],b[N],ma,mb;
int f[N][N][N*2],p[N][N*2],dp[N][N*2];
int jc[N*10],inv[N*10];
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 C(int x,int y){return jc[x]*inv[y]%mod*inv[x-y]%mod;}
signed main(){
    freopen("black.in","r",stdin);
    freopen("black.out","w",stdout);
    scanf("%lld",&n);
    fo(i,1,n)scanf("%lld",&a[i]),mb=max(mb,a[i]);
    fo(i,1,n)scanf("%lld",&b[i]),ma=max(ma,b[i]);
    fo(i,0,ma)f[i][0][i]=1;
    fo(i,0,ma)
        fo(j,0,mb)
            fo(k,0,i+j)
                fo(o,0,ma-i)(f[i+o][j+1][o+(o>=k)]+=f[i][j][k])%=mod;//cout<<i<<" "<<j<<" "<<k<<" "<<o<<" "<<f[i][j][k]<<endl;
    //cout<<f[1][1][0]<<" "<<f[1][1][2]<<endl;
    jc[0]=1;fo(i,1,1000)jc[i]=jc[i-1]*i%mod;
    inv[0]=1;inv[1000]=ksm(jc[1000],mod-2);
    fu(i,1000-1,1)inv[i]=inv[i+1]*(i+1)%mod;
    fo(i,1,n)fo(j,0,ma+mb)p[i][j]=f[b[i]][a[i]][j]*ksm(C(a[i]+b[i],a[i]),mod-2)%mod;//cout<<C(a[i]+b[i],a[i])<<endl;
    dp[0][0]=1;
    fo(i,0,n-1){
        fo(j,0,ma+mb){
            if(!dp[i][j])continue;
            fo(k,0,ma+mb){
                dp[i+1][j^k]=(dp[i+1][j^k]+dp[i][j]*p[i+1][k])%mod;
            }
        }
    }
    printf("%lld",(1+mod-dp[n][0])%mod);
}

打怪

这个我好像不会处理要先杀哪个,然后直接把攻击×生命最大的干掉了,80pts

其实斜率优化一下就行了,好像是要用到CDQ的,也可以正反各一边

但是我只走了一边,注意统计答案时,用的是原来序列中的顺序,仔细读代码

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define re register int
const int N=3e5+5;
int n,b;
int nwv,nwt,ans,res;
int fro[N],beh[N];
struct node{
    int a,d,t,e,id;
    long double v;
    node(){}
}sca[N];
int sta[N],top;
bool comp1(node x,node y){return x.v>y.v;}
bool comp2(node x,node y){return x.t!=y.t?x.t<y.t:x.e>y.e;}
double get(int x,int y){return 1.0*(sca[y].e-sca[x].e)/(sca[y].t-sca[x].t);}
int sol(int x,int y){
    if(sca[x].id<sca[y].id)return sca[x].e+sca[y].e-sca[x].t*sca[y].a;
    else return sca[x].e+sca[y].e-sca[y].t*sca[x].a;
}
signed main(){
    freopen("fittest.in","r",stdin);
    freopen("fittest.out","w",stdout);
    scanf("%lld%lld",&n,&b);
    for(re i=1;i<=n;i++){
        scanf("%lld%lld",&sca[i].a,&sca[i].d);
        sca[i].t=(sca[i].d-1)/b+1;
        sca[i].v=1.0*sca[i].a/sca[i].t;
    }
    sort(sca+1,sca+n+1,comp1);
    for(re i=1;i<=n;i++)fro[i]=fro[i-1]+sca[i].t;
    for(re i=n;i>=1;i--)beh[i]=beh[i+1]+sca[i].a;
    for(re i=1;i<=n;i++){
        sca[i].e=fro[i]*sca[i].a-sca[i].a+beh[i+1]*sca[i].t;
        sca[i].id=i;
        nwt+=sca[i].t;ans+=nwt*sca[i].a-sca[i].a;
    }
    sort(sca+1,sca+n+1,comp2);
    for(re i=1;i<n;i++){
        if(sca[i].t!=sca[i-1].t){
            while(top>1&&get(sta[top-1],sta[top])<get(sta[top],i))top--;
            sta[++top]=i;
        }
        int l=1,r=top,mid;
        while(l<r){
            mid=l+r+1>>1;
            if(sca[i+1].a<=get(sta[mid-1],sta[mid]))l=mid;
            else r=mid-1;
        }
        res=max(res,sol(sta[l],i+1));
    }
    printf("%lld",ans-res);
}
posted @ 2021-09-18 06:37  fengwu2005  阅读(32)  评论(0编辑  收藏  举报