1. 程式人生 > >noip2013 提高組

noip2013 提高組

還要 傳送門 hide one insert hid 數據 離散 algorithm

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\n",(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\n",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\n",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\n",max(f[n][0],f[n][1]));
    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\n",max(f[n][0],f[n][1]));
    return 0;
}
View Code

T6 華容道 題目傳送門

這道題黃學長都棄坑了 我糾結什麽呢 以後補吧 hzwer

noip2013 提高組