noip模拟66[依旧很菜]

noip模拟66 solutions

话说这几次一直改不完题,今天也只是改了三道题

只能先咕掉,以后再改了。。

今天的考试,时间分配极其不好,还有一个就是我思想的问题

做到最后发现啥也不会,然后就不想做了,导致我直接交了前两个题就走人了

以后一定要做完题,要不然会非常后悔的

T1 接力比赛

这个我知道是个背包,但是我直接干了个裸的上去,一点优化都没带

然后导致我没有切掉,,,

下次遇见题一定要记得优化暴力

AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#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=1005;
const int M=1e6;
int n,m,tot,ans;
int wn[N],vn[N],sn[N];
int wm[N],vm[N],sm[N];
int f[M],g[M];
signed main(){
    #ifdef oj
        freopen("game.in","r",stdin);
        freopen("game.out","w",stdout);
    #endif
    scanf("%lld%lld",&n,&m);
    fo(i,1,n)scanf("%lld%lld",&wn[i],&vn[i]),sn[i]=sn[i-1]+wn[i];
    fo(i,1,m)scanf("%lld%lld",&wm[i],&vm[i]),sm[i]=sm[i-1]+wm[i];
    memset(f,-0x3f,sizeof(f));f[0]=0;
    memset(g,-0x3f,sizeof(g));g[0]=0;
    fo(i,1,n)fu(j,sn[i],wn[i])f[j]=max(f[j],f[j-wn[i]]+vn[i]);
    fo(i,1,m)fu(j,sm[i],wm[i])g[j]=max(g[j],g[j-wm[i]]+vm[i]);
    fo(i,1,min(sn[n],sm[m]))ans=max(ans,f[i]+g[i]);
    printf("%lld",ans);
}

T2 树上竞技

这个题太妙了,那个组合数!!!

其实对于许多组合数来说,当你给他赋予一个实际含义的时候,

如果需要递推,或者需要求和,这样就会变得很简单

所以要不断地积累一些例子,让在考场上应用组合数的时候更加得心应手

AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#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=1e9+7;
int n,m;
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 g[N],jc[N],inv[N];
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){if(x<y)return 0;return jc[x]*inv[y]%mod*inv[x-y]%mod;}
int siz[N],ans;
void dfs(int x,int f){
    siz[x]=1;
    for(int i=head[x];i;i=nxt[i]){
        int y=to[i];
        if(y==f)continue;
        dfs(y,x);siz[x]+=siz[y];
    }
    ans=(ans+g[siz[x]]+g[n-siz[x]])%mod;
    if(m%2==0)ans=(ans+C(siz[x],m/2)*C(n-siz[x],m/2)%mod*(m/2)%mod)%mod;
}
signed main(){
    #ifdef oj
        freopen("meeting.in","r",stdin);
        freopen("meeting.out","w",stdout);
    #endif
    scanf("%lld%lld",&n,&m);
    fo(i,2,n){
        int x;scanf("%lld",&x);
        add_edg(i,x);add_edg(x,i);
    }
    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;
    if(m>2)g[1]=C(n-1,m-1);
    fo(i,1,n-1)g[i+1]=(g[i]+mod-C(i-1,(m-1)/2-1)*C(n-i-1,m-(m-1)/2-1)%mod)%mod;
    fo(i,1,n)g[i]=g[i]*i%mod;
    dfs(1,0);printf("%lld",ans);
}

T3 虚构推理

有一点点小小的后悔。

这道题我考场上看到非常的麻烦,就直接跳过了

但是后来一看好像还挺简单的,暴力分还是挺好拿的

我没有打正解,直接在时间复杂度可以接受的范围内枚举的

AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#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=50005;
int n,ah,am,as;
double h[N],m[N],ans=1000000000.0;
void sol(double i,double j,double k){
    double th=i*30.0+j*0.5+k*0.5/60.0;
    double tm=j*6.0+k*0.1;
    if(th>=180.0)th-=180.0;
    else th+=180.0;
    if(tm>=180.0)tm-=180.0;
    else tm+=180.0;
    int ph=upper_bound(h+1,h+n+1,th)-h-1;
    int pm=upper_bound(m+1,m+n+1,tm)-m-1;
    double r1=180.0-th+h[ph];if(r1<0)r1+=360.0;if(r1>=360.0)r1-=360.0;
    double r2=180.0-h[ph+1]+th;if(r2<0)r2+=360.0;if(r2>=360.0)r2-=360.0;
    double r3=180.0-tm+m[pm];if(r3<0)r3+=360.0;if(r3>=360.0)r3-=360.0;
    double r4=180.0-m[pm+1]+tm;if(r4<0)r4+=360.0;if(r4>=360.0)r4-=360.0;
    if(360.0-r1<r1)r1=360.0-r1;
    if(360.0-r3<r3)r3=360.0-r3;
    ans=min(ans,max(max(r1,r2),max(r3,r4)));
}
signed main(){
    #ifdef oj
        freopen("unreal.in","r",stdin);
        freopen("unreal.out","w",stdout);
    #endif
    scanf("%d",&n);
    fo(i,1,n){
        scanf("%d",&ah);getchar();
        scanf("%d",&am);getchar();
        scanf("%d",&as);getchar();ah%=12;
        //cout<<ah<<":"<<am<<":"<<as<<endl;
        h[i]=ah*30.0+am*0.5+as*0.5/60.0;
        m[i]=am*6.0+as*0.1;
    }
    sort(h+1,h+n+1);h[0]=h[n];h[n+1]=h[1];
    sort(m+1,m+n+1);m[0]=m[n];m[n+1]=m[1];
    fo(i,0,11)fo(j,0,59)for(double k=0;k<60;k+=0.01)sol(i,j,k);
    printf("%.10lf",ans);
}

T4 记忆碎片

//我还没有改

改完啦改完啦----10.08

这个\(dp\)确实是妙哉

首先我们对于这个图一无所知,但是我们知道一些在最小生成树上的边

这个就给了我们一个限制,我们从小到大一条一条边的加入图中

如果当前加入的不是树边,那么这个边只能连接两个在同一连通块中的点

如果是树边,就必须连接两个连通块!!!

这样我们先预处理这张图中可能会出现的连通性的种类,也就是对于\(n\)的整数划分

然后用\(map\)映射到一个数上,对于这个东西\(dp\)并转移

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fxt(i,x,y) for(int i=(x);i<=(y);i++)
#define pyt(i,x,y) for(int i=(x);i>=(y);i--)
const int N=45;
const int M=45*45;
const int T=45*45*20;
const int mod=1e9+7;
int n,m,knd,f[M][M*40],e[M*20];
bool vis[M];
vector<int> s[M*20],v;
map<vector<int>,int> mp;
void dfs(int l,int r){
    if(!r){
        s[++knd]=v;mp.insert(make_pair(v,knd));
        fxt(i,0,(int)v.size()-1)e[knd]+=v[i]*(v[i]-1)/2;
        return ;
    }
    if(r<l)return ;
    fxt(i,l,r){
        v.push_back(i);
        dfs(i,r-i);
        v.pop_back();
    }
}
signed main(){
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);
    scanf("%lld",&n);
    m=n*(n-1)/2;
    fxt(i,1,n-1){
        int x;scanf("%lld",&x);
        vis[x]=true;
    }
    dfs(1,n);f[0][1]=1;
    fxt(i,1,m){
        fxt(j,1,knd){
            if(!f[i-1][j])continue;
            if(!vis[i]){
                f[i][j]=(f[i][j]+f[i-1][j]*(e[j]-i+1))%mod;
                continue;
            }
            fxt(x,0,(int)s[j].size()-1){
                fxt(y,x+1,(int)s[j].size()-1){
                    vector<int> tmp;tmp.clear();
                    tmp.push_back(s[j][x]+s[j][y]);
                    fxt(k,0,(int)s[j].size()-1)
                        if(k!=x&&k!=y)tmp.push_back(s[j][k]);
                    sort(tmp.begin(),tmp.end());
                    int pos=mp.find(tmp)->second;
                    f[i][pos]=(f[i][pos]+f[i-1][j]*s[j][x]%mod*s[j][y]%mod)%mod;
                }
            }
        }
    }
    printf("%lld",f[m][knd]);
}
posted @ 2021-10-03 06:20  fengwu2005  阅读(121)  评论(0编辑  收藏  举报