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\n",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?'\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\n",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\n",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\n",ans);
    }
    return 0;
}
posted @ 2019-06-04 11:46  QwQGJH  阅读(177)  评论(0编辑  收藏  举报