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;
}