zoukankan      html  css  js  c++  java
  • NOIP2016题解

    玩具迷题

    直接按照题目模拟即可.

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<iostream>
    #include<queue>
    #include<algorithm>
    #include<map>
    #include<set>
    using namespace std;
    #define ll long long
    #define re register
    #define file(a) freopen(a".in",,"r",stdin);freopen(a".out","w",stdout)
    inline int gi(){
    	int f=1,sum=0;char ch=getchar();
    	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    	return f*sum;
    }
    const int N=100010;
    int n,m,p[N];char name[N][13];
    int main(){
    	n=gi();m=gi();
    	for(int i=0;i<n;i++)p[i]=gi(),scanf("%s",name[i]);int pos=0;
    	while(m--){
    		int a=gi(),s=gi();
    		if(p[pos]^a)pos=(pos+s)%n;
    		else pos=(pos-s+n)%n;
    	}
    	printf("%s
    ",name[pos]);
    	return 0;
    }
    

    天天爱跑步

    可能是(NOIp2016)里面最难的吧.

    考虑一条路径对点的贡献,显然路径可以拆成向上的和向下的,向上的就是(dep_S=dep_i+w_i)的时候有贡献,向下的相对应的推一下,开个桶统计一下就好了.

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<iostream>
    #include<queue>
    #include<algorithm>
    #include<map>
    #include<set>
    using namespace std;
    #define ll long long
    #define re register
    #define file(a) freopen(a".in",,"r",stdin);freopen(a".out","w",stdout)
    inline int gi(){
    	int f=1,sum=0;char ch=getchar();
    	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    	return f*sum;
    }
    const int N=1000010,Mx=300010;
    int f[N][20],dep[N],b[N],ans[N],front[N],cnt,S[N],n,m,w[N];
    vector<int>v1[N],v2[N],v3[N];
    struct node{int to,nxt;}e[N<<1];
    void Add(int u,int v){e[++cnt]=(node){v,front[u]};front[u]=cnt;}
    struct ques{int u,v,lca;}p[N];
    void dfs(int u,int ff){
    	dep[u]=dep[ff]+1;f[u][0]=ff;
    	for(int i=front[u];i;i=e[i].nxt){int v=e[i].to;if(v==ff)continue;dfs(v,u);}
    }
    void dfs1(int u,int ff){
    	int pre=b[dep[u]+w[u]+Mx];
    	for(int i=front[u];i;i=e[i].nxt){
    		int v=e[i].to;if(v==ff)continue;
    		dfs1(v,u);
    	}
    	b[dep[u]+Mx]+=S[u];
    	ans[u]+=b[dep[u]+w[u]+Mx]-pre;
    	for(int i=0;i<v1[u].size();i++)
    		b[dep[v1[u][i]]+Mx]--;
    }
    void dfs2(int u,int ff){
    	int pre=b[w[u]-dep[u]+Mx];
    	for(int i=front[u];i;i=e[i].nxt){
    		int v=e[i].to;if(v==ff)continue;
    		dfs2(v,u);
    	}
    	for(int i=0;i<v2[u].size();i++)
    		b[v2[u][i]+Mx]++;
    	ans[u]+=b[w[u]-dep[u]+Mx]-pre;
    	for(int i=0;i<v3[u].size();i++)
    		b[v3[u][i]+Mx]--;
    }
    int lca(int x,int y){
    	if(dep[x]<dep[y])swap(x,y);
    	for(int i=18;~i;i--)
    		if(dep[x]-(1<<i)>=dep[y])x=f[x][i];
    	if(x==y)return x;
    	for(int i=18;~i;i--)
    		if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    	return f[x][0];
    }
    int main(){
    	n=gi();m=gi();
    	for(int i=1;i<n;i++){
    		int u=gi(),v=gi();Add(u,v);Add(v,u);
    	}
    	dep[1]=-1;dfs(1,1);
    	for(int j=1;j<=18;j++)
    		for(int i=1;i<=n;i++)
    			f[i][j]=f[f[i][j-1]][j-1];
    	for(int i=1;i<=n;i++)w[i]=gi();
    	for(int i=1;i<=m;i++){
    		int u=gi(),v=gi();
    		int Lca=lca(u,v);
    		int Dis=dep[u]+dep[v]-2*dep[Lca];
    		p[i].u=u;p[i].v=v;p[i].lca=Lca;
    		v1[Lca].push_back(u);S[u]++;
    		v2[v].push_back(Dis-dep[v]);
    		v3[Lca].push_back(Dis-dep[v]);
    	}
    	dfs1(1,1);dfs2(1,1);
    	for(int i=1;i<=m;i++)
    		if(dep[p[i].u]==dep[p[i].lca]+w[p[i].lca])ans[p[i].lca]--;
    	for(int i=1;i<=n;i++)printf("%d%c",ans[i],i==n?'
    ':' ');
    	return 0;
    }
    

    换教室

    简单期望(dp),直接写就好了.

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<iostream>
    #include<queue>
    #include<algorithm>
    #include<map>
    #include<set>
    using namespace std;
    #define ll long long
    #define re register
    #define file(a) freopen(a".in",,"r",stdin);freopen(a".out","w",stdout)
    inline int gi(){
    	int f=1,sum=0;char ch=getchar();
    	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    	return f*sum;
    }
    const int N=2010;
    int g[N][N],n,m,v,e,d[N],c[N];
    double K[N],dp[N][N][2];
    int main(){
    	n=gi();m=gi();v=gi();e=gi();memset(g,63,sizeof(g));
    	for(int i=1;i<=n;i++)c[i]=gi();for(int i=1;i<=n;i++)d[i]=gi();
    	for(int i=1;i<=n;i++)scanf("%lf",&K[i]);
    	for(int i=1;i<=e;i++){
    		int a=gi(),b=gi(),w=gi();
    		g[a][b]=g[b][a]=min(g[a][b],w);
    	}
    	for(int k=1;k<=v;k++)
    		for(int i=1;i<=v;i++)
    			for(int j=1;j<=v;j++)
    				g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
    	for(int i=1;i<=v;i++)g[i][i]=g[0][i]=g[i][0]=0;
    	for(int i=0;i<=n;i++)
    		for(int j=0;j<=m;j++)
    			dp[i][j][0]=dp[i][j][1]=1e18;
    	dp[1][0][0]=0;dp[1][1][1]=0;
    	for(int i=2;i<=n;i++)
    	{
    		dp[i][0][0]=dp[i-1][0][0]+g[c[i-1]][c[i]];
    		for(int j=1;j<=min(m,i);j++){
    			int Cl=c[i-1],Dl=d[i-1],C=c[i],D=d[i];
    			dp[i][j][0]=min(dp[i][j][0],min(dp[i-1][j][0]+g[Cl][C],dp[i-1][j][1]+g[Cl][C]*(1-K[i-1])+g[Dl][C]*K[i-1]));
    			dp[i][j][1]=min(dp[i][j][1],min(dp[i-1][j-1][0]+g[Cl][C]*(1-K[i])+g[Cl][D]*K[i],dp[i-1][j-1][1]+g[Cl][C]*(1-K[i])*(1-K[i-1])+g[Cl][D]*K[i]*(1-K[i-1])+g[Dl][C]*K[i-1]*(1-K[i])+g[Dl][D]*K[i-1]*K[i]));
    		}
    	}
    	double ans=1e18;
    	for(int i=0;i<=m;i++){
    		ans=min(ans,min(dp[n][i][0],dp[n][i][1]));
    	}
    	printf("%.2lf
    ",ans);
    	return 0;
    }
    

    组合数问题

    预处理然后二维前缀和,没了...

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<iostream>
    #include<queue>
    #include<algorithm>
    #include<map>
    #include<set>
    using namespace std;
    #define ll long long
    #define re register
    #define file(a) freopen(a".in",,"r",stdin);freopen(a".out","w",stdout)
    inline int gi(){
    	int f=1,sum=0;char ch=getchar();
    	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    	return f*sum;
    }
    const int N=2010,Mx=2000;
    int k,c[N][N],sum[N][N];
    int main(){
    	int T=gi();k=gi();c[0][0]=1;
    	for(int i=1;i<=Mx;i++){
    		c[i][0]=c[i][i]=1;
    		for(int j=1;j<i;j++)
    			c[i][j]=(c[i-1][j]+c[i-1][j-1])%k;
    	}
    	for(int i=0;i<=Mx;i++)
    		for(int j=0;j<=i;j++)
    			if(!c[i][j])sum[i][j]=1;
    	for(int i=1;i<=Mx;i++)
    		for(int j=1;j<=Mx;j++)
    			sum[i][j]=sum[i-1][j]+sum[i][j-1]+sum[i][j]-sum[i-1][j-1];
    	while(T--){
    		int n=gi(),m=gi();
    		printf("%d
    ",sum[n][m]);
    	}
    	return 0;
    }
    

    蚯蚓

    考虑一个客观事实:长的切了后一定比短的长(长对长,短对短).

    那么我们搞3个单调队列,维护原来的,割了后长的,割了后短的,模拟就好了.

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<iostream>
    #include<queue>
    #include<algorithm>
    #include<map>
    #include<set>
    using namespace std;
    #define ll long long
    #define re register
    #define file(a) freopen(a".in",,"r",stdin);freopen(a".out","w",stdout)
    #define int ll
    inline int gi(){
    	int f=1,sum=0;char ch=getchar();
    	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    	return f*sum;
    }
    const int N=8000010;
    int n,m,q,u,v,t,a[N],ans[N];
    queue<int>q1,q2,q3;
    int getmax(){
    	int x1=-1e18,x2=-1e18,x3=-1e18;
    	if(!q1.empty())x1=q1.front();
    	if(!q2.empty())x2=q2.front();
    	if(!q3.empty())x3=q3.front();
    	if(x1>=x2 && x1>=x3){q1.pop();return x1;}
    	if(x2>=x1 && x2>=x3){q2.pop();return x2;}
    	q3.pop();return x3;
    }
    void put(int x,int y){
    	if(x>y)swap(x,y);
    	q2.push(x);q3.push(y);
    }
    signed main(){
    	n=gi();m=gi();q=gi();u=gi();v=gi();t=gi();
    	for(int i=1;i<=n;i++)a[i]=gi();sort(a+1,a+n+1);for(int i=n;i;i--)q1.push(a[i]);
    	int tot=0,cnt=0;
    	for(int i=1;i<=m;i++){
    		ans[i]=getmax()+tot;
    		int j=ans[i]*u/v,k=ans[i]-j;
    		tot+=q;
    		put(j-tot,k-tot);
    	}
    	while(!q1.empty() || !q2.empty() || !q3.empty())a[++cnt]=getmax()+tot;
    	for(int i=t;i<=m;i+=t)printf("%lld ",ans[i]);puts("");
    	for(int i=t;i<=cnt;i+=t)printf("%lld ",a[i]);puts("");
    	return 0;
    }
    

    愤怒的小鸟

    因为两只猪确定一个方程,然后爆搜就好了,式子用二次函数的推就好了.

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<iostream>
    #include<queue>
    #include<algorithm>
    #define ll long long
    #define re register
    using namespace std;
    inline int gi(){
        int f=1,sum=0;char ch=getchar();
        while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
        return f*sum;
    }
    const int Inf=1000000000+10,maxn=110;
    double pwxa[maxn],x[maxn],y[maxn],pwxb[maxn],tx[maxn],ty[maxn];
    const double eps=1e-8;
    bool judge(double x,double y){
        return fabs(x-y)<=eps;
    }
    int ans,n,m;
    void dfs(int pig,int got,int less){
        int flag=0;
        if(got+less>=ans)return;
        if(pig>n){
            ans=got+less;return;
        }
        for(re int i=1;i<=got;i++)
            if(judge(pwxa[i]*x[pig]*x[pig]+pwxb[i]*x[pig],y[pig])){
                dfs(pig+1,got,less);
                flag=1;
                break;
            }
        if(!flag){
            for(re int i=1;i<=less;i++){
                //Choose i and Pig
                //i:tx[i],ty[i];
                //Pig:x[Pig],y[Pig]
                double xx=tx[i],yy=ty[i];
                double a=(ty[i]-y[pig]/x[pig]*tx[i])/(tx[i]*(tx[i]-x[pig])),b=(y[pig]-a*x[pig]*x[pig])/x[pig];
                if(a>=0)continue;
                for(re int j=i;j<less;j++)
                    tx[j]=tx[j+1],ty[j]=ty[j+1];
                pwxa[got+1]=a;pwxb[got+1]=b;
                dfs(pig+1,got+1,less-1);
                for(re int j=less;j>=i+1;j--)
                    tx[j]=tx[j-1],ty[j]=ty[j-1];
                tx[i]=xx,ty[i]=yy;
            }
        }
        tx[less+1]=x[pig];
        ty[less+1]=y[pig];
        dfs(pig+1,got,less+1);
    }
    int main(){
        int T=gi();
        while(T--){
            ans=Inf;
            n=gi(),m=gi();
            for(re int i=1;i<=n;i++)scanf("%lf%lf",&x[i],&y[i]);
            dfs(1,0,0);
            printf("%d
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    趣味网站、趣味应用
    趣味网站、趣味应用
    论文写作的句型
    Python Tricks(二十一)—— 排列组合的计算
    Python Tricks(二十一)—— 排列组合的计算
    辨异 —— 有两人生日在同一天、只有两人生日在同一天
    辨异 —— 有两人生日在同一天、只有两人生日在同一天
    品味电影
    品味电影
    HDU 4414 Finding crosses (DFS + BFS)
  • 原文地址:https://www.cnblogs.com/mleautomaton/p/10972662.html
Copyright © 2011-2022 走看看