noip2013 提高组

T1 转圈游戏 题目传送门

果不其然 第一题还是模拟题 一波快速幂解决问题

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
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,x;
int qmod(int a,int b,int c){
    int ans=1;
    while(b){
        if(b&1) ans=ans*a%c;
        b=b/2;
        a=a*a%c;
    }
    return ans;
}
int main()
{
    n=read(); m=read(); k=read(); x=read(); 
    int v=qmod(10,k,n);
    printf("%d
",(v*m+x)%n);
    return 0;
}
View Code

T2 火柴排队 题目传送门

 这是道树状数组求逆序数对的题目 当然还要加一波离散化就好了 不过这题的离散化很玄学哇 2333

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int M=100007,mod=99999997;
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;
}
struct node{int w,pos;}a[M],b[M];
bool cmp(node a,node b){return a.w<b.w;}
int c[M],sum[M],n;
LL ans;
int lowbit(int x){return x&-x;}
void insert(int x){
    while(x<=n){
        sum[x]++;
        x+=lowbit(x);
    }
}
int push_sum(int x){
    int ans=0;
    while(x){ans+=sum[x]; x-=lowbit(x);}
    return ans;
}
int main()
{
    n=read(); 
    for(int i=1;i<=n;i++) a[i].w=read(),a[i].pos=i;
    for(int i=1;i<=n;i++) b[i].w=read(),b[i].pos=i;
    sort(a+1,a+1+n,cmp); sort(b+1,b+1+n,cmp);
    for(int i=1;i<=n;i++) c[a[i].pos]=b[i].pos;
    for(int i=1;i<=n;i++){
        insert(c[i]);
        ans=(ans+i-push_sum(c[i]))%mod;
    }
    printf("%lld
",ans);
    return 0;
}
View Code

T3 货车运输 题目传送门

几乎是裸的lca吧 用lca维护一波最近公共祖先和路径最小值就好了

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int M=150007; 
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 w[M],n,f[M][2]; 
int main()
{
    n=read();
    for(int i=1;i<=n;i++) w[i]=read(),f[i][0]=f[i][1]=1;
    for(int i=1;i<=n;i++)
        for(int j=i-1;j;j--){
            if(w[i]>w[j]) f[i][1]=max(f[i][1],f[j][0]+1);
            if(w[j]>w[i]) f[i][0]=max(f[i][0],f[j][1]+1);
            if(f[i][0]!=1&&f[i][1]!=1) break;
        }
    printf("%d
",max(f[n][0],f[n][1]));
    return 0;
}
View Code

T4 积木大赛  题目传送门

这道题就是我们只考虑相邻两列h1 h2 容易证明他的无后效性

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int M=150007; 
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 w[M],n,f[M][2]; 
int main()
{
    n=read();
    for(int i=1;i<=n;i++) w[i]=read(),f[i][0]=f[i][1]=1;
    for(int i=1;i<=n;i++)
        for(int j=i-1;j;j--){
            if(w[i]>w[j]) f[i][1]=max(f[i][1],f[j][0]+1);
            if(w[j]>w[i]) f[i][0]=max(f[i][0],f[j][1]+1);
            if(f[i][0]!=1&&f[i][1]!=1) break;
        }
    printf("%d
",max(f[n][0],f[n][1]));
    return 0;
}
View Code

当然其实正解我也写了一波 比dp快很多呀 2333

至于为什么是拐点 

这道题就是求一个 大小大小大小或者 小大小大小大 的序列 其中大小是相对于相邻两个数而言

我们可以分情况考虑答案

1. 前一个数是 ‘大’ (定义为last)那么我们下一个数一定要比他小 这时我们考虑当前数 (定义为now)

如果now<last 很明显符合 那么答案++

如果last>=now 那么前面小于last的以及后面能<last的同样能符合now 那么我们完全可以用now代替last

2 前一个数是 ‘下' 同1

所以这个问题就转换成了求拐点数 拐点数+1就是答案了 2333

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int M=100007;
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,v[M];
int f,last,ans;
void solve(){
    int sum=1;
    for(int i=2;i<=n;i++){
        if(f==1&&v[i]<last)  f=-1,sum++;
        if(f==-1&&v[i]>last) f=1,sum++;
        last=v[i];
    }
    ans=max(ans,sum);
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++) v[i]=read();
    last=v[1]; f=1; solve();
    last=v[1]; f=-1; solve();
    printf("%d
",ans);
    return 0;
}
View Code

T5 花匠 题目传送门

正解似乎是算拐点+1 数据随机dp水过
0表示他是作为比较小的那个点 1则相反
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int M=150007; 
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 w[M],n,f[M][2]; 
int main()
{
    n=read();
    for(int i=1;i<=n;i++) w[i]=read(),f[i][0]=f[i][1]=1;
    for(int i=1;i<=n;i++)
        for(int j=i-1;j;j--){
            if(w[i]>w[j]) f[i][1]=max(f[i][1],f[j][0]+1);
            if(w[j]>w[i]) f[i][0]=max(f[i][0],f[j][1]+1);
            if(f[i][0]!=1&&f[i][1]!=1) break;
        }
    printf("%d
",max(f[n][0],f[n][1]));
    return 0;
}
View Code

T6 华容道 题目传送门

 这道题黄学长都弃坑了 我纠结什么呢 以后补吧 hzwer

 
原文地址:https://www.cnblogs.com/lyzuikeai/p/7173157.html