noip2016 提高组

T1 玩具谜题 题目传送门

这道题直接模拟就好了哇 233

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int M=1e5+7;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f;
}
int n,m,k,v,ans=1;
char s[M][25];
int h[M];
int main()
{
    n=read(); m=read();
    for(int i=1;i<=n;i++) h[i]=read(),scanf("%s",s[i]);//0朝内1朝外 
    for(int i=1;i<=m;i++){
        k=read(); v=read();
        if(!k) v=-v;
        if(h[ans]) v=-v;
        ans=ans+v;
        if(ans<1) ans=ans+n;
        if(ans>n) ans=ans-n; 
    }
    printf("%s",s[ans]);
    return 0;
}
View Code

 T2  天天爱跑步 题目传送门

这道题我 真的 看不懂..... 跳 以后填坑

T3  换教室  最短路+dp  题目传送门

这道题是道期望dp f【i】【j】【k】代表到第i个时段换了j个教师k代表当前点换不换(1换0不换) 然后就是一波递推了 

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int M=2007;
const double inf=1e15;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f;
}
int n,m,v,s,c[M],d[M];
double k[M],f[M][M][2],dis[M][M],w;
void prepare(){
    for(int i=1;i<=v;i++)
     for(int j=1;j<=v;j++)
      dis[i][j]=(i==j)?0:inf;
    for(int i=1;i<=n;i++)
     for(int j=0;j<=m;j++)
      f[i][j][0]=f[i][j][1]=inf;
    f[1][0][0]=0; f[1][1][1]=0;
//    for(int i=1;i<=n;i++,printf("
")) for(int j=1;j<=v;j++) printf("[%.2lf %.2lf] ",f[i][j][0],f[i][j][1]);
}
void floyd(){
    for(int k=1;k<=v;k++)
     for(int i=1;i<=v;i++)
      for(int j=1;j<=v;j++)
       dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
//    for(int i=1;i<=v;i++,printf("
")) for(int j=1;j<=v;j++) printf("%.2lf ",dis[i][j]);
}
int main()
{
    int x,y; 
    n=read(); m=read(); v=read(); s=read();
    for(int i=1;i<=n;i++) c[i]=read();
    for(int i=1;i<=n;i++) d[i]=read();
    for(int i=1;i<=n;i++) scanf("%lf",&k[i]);
    prepare();  
    for(int i=1;i<=s;i++){
        x=read(); y=read(); scanf("%lf",&w); 
        dis[x][y]=dis[y][x]=min(dis[x][y],w); 
    }
    floyd();
    for(int i=2;i<=n;i++){
        for(int j=0;j<=m;j++){
            if(!j) {f[i][j][0]=min(f[i][j][0],f[i-1][j][0]+dis[c[i-1]][c[i]]); continue;}
            f[i][j][0]=min(f[i][j][0],f[i-1][j][0]+dis[c[i-1]][c[i]]);
            f[i][j][0]=min(f[i][j][0],f[i-1][j][1]+dis[d[i-1]][c[i]]*k[i-1]+dis[c[i-1]][c[i]]*(1-k[i-1]));
            f[i][j][1]=min(f[i][j][1],f[i-1][j-1][0]+dis[c[i-1]][d[i]]*k[i]+dis[c[i-1]][c[i]]*(1-k[i]));
            double d1=k[i]*k[i-1]*dis[d[i-1]][d[i]],d2=k[i]*(1-k[i-1])*dis[c[i-1]][d[i]];
            double d3=(1-k[i])*k[i-1]*dis[d[i-1]][c[i]],d4=(1-k[i])*(1-k[i-1])*dis[c[i-1]][c[i]];
            f[i][j][1]=min(f[i][j][1],f[i-1][j-1][1]+d1+d2+d3+d4);
        }
    }
    double ans=inf;
    for(int i=0;i<=m;i++) ans=min(ans,f[n][i][0]),ans=min(ans,f[n][i][1]);
    printf("%.2lf
",ans);
    return 0;
}
View Code

T4  组合数问题 题目传送门

这道题 搜索打一波发现是个类似杨辉三角的东西 然后就维护一波前缀和方便计算就好了哇 其实可以跑两波实现o(1) 查询 不过 我懒啦 233

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int M=2007;
LL read(){
    LL ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f;
}
LL f[M][M],sum[M][M];
LL n,m,T,k,ans;
void prepare(){
    for(LL i=0;i<M;i++) f[i][0]=1;
    for(LL i=1;i<M;i++)
     for(LL j=1;j<=i;j++){
         f[i][j]=(f[i-1][j]+f[i-1][j-1])%k;
         if(!f[i][j]) sum[i][j]=1;
         sum[i][j]+=sum[i][j-1];
     }
}
int main()
{
    for(T=read(),k=read(),prepare();T;T--){
        n=read(); m=read(); ans=0;
        for(LL i=1;i<=n;i++) ans=ans+sum[i][min(i,m)];
        printf("%lld
",ans);
    }
    return 0;
}
View Code

 T5  蚯蚓 题目传送门

这道题其实就是维护三个队列q1是原队列 按从小到达sort一波 以后都不会有更新了 q2,q3分别储存砍完的前后半段 可以证明两个队列都是单调递减的 然后整体的加转化成个体的减的好了

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int M=1e7+7;
LL read(){
    LL ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f;
}
LL n,m,q,u,v,k;
LL h1=1,h2=1,h3=1,t2,t3;
LL q1[M],q2[M],q3[M];
bool cmp(LL a,LL b){return a>b;}
LL push_max(LL x){
    LL sum=-0x3f3f3f3f3f3f3f3f;
    if(h1<=n) sum=max(sum,q1[h1]);
    if(h2<=t2) sum=max(sum,q2[h2]);
    if(h3<=t3) sum=max(sum,q3[h3]);
    if(h1<=n&&q1[h1]==sum) h1++;
    else if(h2<=t2&&q2[h2]==sum) h2++;
    else h3++;
    //printf("[%lld]
",sum+q*(x-1));
    return sum+q*(x-1);
}
int main()
{
    n=read(); m=read(); q=read(); u=read(); v=read(); k=read();
    for(int i=1;i<=n;i++) q1[i]=read();
    sort(q1+1,q1+1+n,cmp);
    //for(int i=1;i<=n;i++) printf("[%d] ",q1[i]);
    for(LL i=1;i<=m;i++){
        LL sum=push_max(i);
        if(i%k==0) printf("%lld ",sum);
        LL now=sum*u/v;
        //printf("[%lld %lld]
",now,sum-now);
        q2[++t2]=now-i*q; q3[++t3]=sum-now-i*q;
        
    }printf("
");
    for(LL i=1;i<=n+m;i++){
        LL sum=push_max(m+1);
        if(i%k==0) printf("%lld ",sum);
    }
    return 0;
}
View Code

 当然优先队列也可以打部分分 但是因为m太大了 nlog(n+m) 会T 只能拿六十分 贴一波T的代码啦

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define LL long long
using namespace std;
const int M=1e7+7;
LL read(){
    LL ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f;
}
LL x;
struct node{
    LL w;
    bool operator < (const node &x)const {return w<x.w;}
};
priority_queue<node>qu;
int n,m,q,u,v,k;
int main()
{
    n=read(); m=read(); q=read(); u=read(); v=read(); k=read();
    for(int i=1;i<=n;i++) x=read(),qu.push((node){x});
//    while(!qu.empty()){node x=qu.top(); printf("%lld
",x.w); qu.pop();}
    for(int i=1;i<=m;i++){
        node x=qu.top(); qu.pop();
        LL sum=x.w+(i-1)*q,now=sum*u/v,cur=sum-now;
        qu.push((node){now-i*q});
        qu.push((node){cur-i*q});
        if(i%k==0) printf("%lld ",sum);
    }printf("
");
    for(int i=1;i<=n+m;i++){
        node x=qu.top(); qu.pop();
        LL sum=x.w+m*q;
        if(i%k==0) printf("%lld ",sum);
    }
    return 0;
}
View Code

 T6 愤怒的小鸟 题目传送门

这是一道状压dp g【i】【j】表示经过i,j两个点的二次函数一共能经过的点数 

然后根据这个可以推出一波答案 不过要记得算一只鸟只打死一只猪的情况就好了

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int M=25;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f;
}
int T,n,m;
int g[M][M],f[1<<M],id[M];
double x[M],y[M],a,b;
bool pd(double x,double y){return fabs(x-y)<1e-6;}
void push_ans(){
    n=read(); m=read();
    for(int i=1;i<=n;i++) scanf("%lf %lf",&x[i],&y[i]);
    memset(g,0,sizeof(g));
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n;j++){
            if(pd(x[i],x[j])) continue;
            a=(y[i]/x[i]-y[j]/x[j])/(x[i]-x[j]);
            if(a>=0) continue;
            b=y[i]/x[i]-a*x[i];
            int sum=0;
            for(int k=1;k<=n;k++) if(pd(a*x[k]+b,y[k]/x[k])) sum+=id[k];
            g[i][j]=sum;
        }
    }
    memset(f,0x3f,sizeof(f));
    f[0]=0;
    for(int k=0;k<(1<<n);k++)
     for(int i=1;i<=n;i++){
        if(id[i]&k) continue;
        for(int j=i+1;j<=n;j++) f[k|g[i][j]]=min(f[k|g[i][j]],f[k]+1);
        f[id[i]|k]=min(f[id[i]|k],f[k]+1);
     }
    printf("%d
",f[(1<<n)-1]);
}
int main()
{
    for(int i=1;i<M;i++) id[i]=1<<(i-1);
    for(T=read();T;T--) push_ans();
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/lyzuikeai/p/7123247.html