1. 程式人生 > >10.13NOIP模擬題

10.13NOIP模擬題

pan -a b- getchar eof gcd nbsp bre splay

技術分享圖片

/*
容斥原理
考慮到a[i]要麽不會太大,要麽就對答案貢獻很小 
dfs即可 
*/
#include<bits/stdc++.h> 


#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)

using namespace std;

ll read()
{
    ll ans=0;
    char last= ,ch=getchar();
    while(ch<0 || ch>9)last=ch,ch=getchar();
    while
(ch>=0 && ch<=9)ans=ans*10+ch-0,ch=getchar(); if(last==-)ans=-ans; return ans; } ll gcd(ll a,ll b){return (!b)?a:gcd(b,a%b);} ll ans=0; int n,m,a[25]; ll Gcd(ll a,ll b) { if(!b)return a; return gcd(b,a%b); } void dfs(int dep,ll t,int flag) { if
(t>n)return; if(dep==m+1) { ans+=n/t*flag; return; } dfs(dep+1,t,flag); dfs(dep+1,t/Gcd(t,a[dep])*a[dep],-flag); } int main() { freopen("count.in","r",stdin); freopen("count.out","w",stdout); n=read(); m=read(); rep(i,1,m)a[i]=read(); dfs(
1,1,1); cout<<ans<<endl; return 0; }

技術分享圖片

技術分享圖片
#include<bits/stdc++.h>

#define N 20000007

using namespace std;
int n,k,num,cnt,ans,mx,mn;
int a[N],k_th[N];

inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c>9||c<0){if(c==-)f=-1;c=getchar();}
    while(c>=0&&c<=9){x=x*10+c-0;c=getchar();}
    return x*f;
}

inline bool cmp(int a,int b)
{
    return a>b;
}

int main()
{
    freopen("kth.in","r",stdin);
    freopen("kth.out","w",stdout);
    n=read();k=read();
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=n;i++)
    {
        mx=mn=a[i];
        for(int j=i+1;j<=n;j++)
        {
            if(a[j]>mx) mx=a[j];
            if(a[j]<mn) mn=a[j];
            k_th[++cnt]=mx-mn;
        }
    }
    sort(k_th+1,k_th+cnt+1,cmp);
    printf("%d\n",k_th[k]);
    return 0;
}
30暴力
/*
二分+單調隊列
可以看出對於一個區間[L,R],[L-1,R]的價值一定不比他小
所以答案可以二分,然後判斷是否這個答案是第k大
可以用單調隊列維護最大最小值,對於每一個右端點,
找距離它最近的左端點滿足這個區間的價值<=k,那麽這個左端點往左都是比當前二分出答案大的。
復雜度 O(nlogn) 
*/
#include<iostream>
#include<cstdio>
#include<cstring>

#define N 410007
#define ll long long

using namespace std;
ll n,m,k,ans,cnt;
ll a[N],q1[N],q2[N];

inline ll read()
{
    ll x=0,f=1;char c=getchar();
    while(c>9||c<0){if(c==-)f=-1;c=getchar();}
    while(c>=0&&c<=9){x=x*10+c-0;c=getchar();}
    return x*f;
}

bool judge(int x)
{
    int l=1,r=1,L=1,R=1;
    ll res=0;q1[1]=1,q2[1]=1;
    int Left=1;
    if(x==1) res=1;else res=0;
    for(int i=2;i<=n;i++)
    {
        while(l<=r && a[i]<=a[q1[r]]) --r;
        q1[++r]=i;
        while(L<=R && a[i]>=a[q2[R]]) --R;
        q2[++R]=i;
        
        while(Left<i)
        {
            int tmp1=l,tmp2=L;Left++;
            while(q1[tmp1]<Left) tmp1++;
            while(q2[tmp2]<Left) tmp2++;
            if(a[q2[tmp2]]-a[q1[tmp1]]>=x) l=tmp1,L=tmp2;
            else {Left--;break;} 
        }
        if(a[q2[L]]-a[q1[l]]>=x) res+=Left;
    }
    return res>=k;
}

int main()
{
    freopen("kth.in","r",stdin);
    freopen("kth.out","w",stdout);
    int x,y;
    n=read();k=read();
    for(int i=1;i<=n;i++) a[i]=read();
    int l_=0,r_=1000000000;
    while(l_<=r_)
    {
        int mid=(l_+r_)>>1;
        if(judge(mid))ans=mid,l_=mid+1;
        else r_=mid-1;
    }
    cout<<ans<<endl;
    return 0;
}

技術分享圖片

/*
特別好的思路
考慮如果選定了幾個武器要求這些武器都不被摧毀,判斷是否可能
從左到右判斷,需要無後效性,所以顯然要按攻擊力從小到大放
那麽每放入一個選定的武器後在其後面添加r個比他攻擊力小的武器
若當前找不出r個比它攻擊力小的武器則判斷失敗
以上判斷有個簡單的表示方式:攻擊力第i小的選定武器其攻擊力在所有武器中的排名需
要>=i*(r+1)
狀態很巧妙 dp[i][j]表示前j個武器選了i個且判定合法的戰場貢獻最大值
轉移的時候判斷第j個選不選即可 
*/
#include<bits/stdc++.h>

#define N 5007
#define inf 0x3f3f3f3f

using namespace std;
int n,m,r,ans,cnt;
int dp[N][N];
struct node{
    int f,w;
    bool operator < (const node &a) const{
            return f<a.f;
    }
}p[N];

inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c>9||c<0){if(c==-)f=-1;c=getchar();}
    while(c>=0&&c<=9){x=x*10+c-0;c=getchar();}
    return x*f;
}

int main()
{
    freopen("submax.in","r",stdin);
    freopen("submax.out","w",stdout);
    int T;T=read();
    while(T--)
    {
        n=read();r=read();
        for(int i=1;i<=n;i++) p[i].f=read();
        for(int i=1;i<=n;i++) p[i].w=read();
        sort(p+1,p+n+1);
        m=n/(r+1)+1;ans=0;
        memset(dp,0,sizeof dp);
        for(int i=1;i<=m;i++)
        {
            int R=min(n,i*(r+1));
            for(int j=0;j<=R-1;j++) dp[i][j]=-inf;
            for(int j=R;j<=n;j++) 
              dp[i][j]=max(dp[i][j-1],dp[i-1][j-1]+p[j].w);
            ans=max(ans,dp[i][n]);
        }
        printf("%d\n",ans);
    }
    return 0;
}

技術分享圖片
p noip 提高組模擬賽 day1
1.計數
(count.cpp/c/pas)
1.計數
(count.cpp/c/pas)
時間限制:1s
內存限制:256MB
【問題描述】
給出 m 個數 a[1],a[2],…,a[m]
求 1~n 中有多少數不是 a[1],a[2],…,a[m]的倍數。
【輸入】
輸入文件名為 count.in。
第一行,包含兩個整數:n,m
第二行,包含 m 個數,表示a[1],a[2],…,a[m]
【輸出】
輸出文件名為 count.out。
輸出一行,包含 1 個整數,表示答案
【輸入輸出樣例】
count.in count.out
102
23
3
【數據說明】
對於 60%的數據,1<=n<=10
6
對於另外 20%的數據,m=2
對於 100%的數據,1<=n<=10
9 ,0<m<=20,1<=a[i]<=10 9
更多資 詢 :北京信息學竇老師 QQ3377089232
2.區間第 k 大
(kth.cpp/c/pas)
2.區間第 k 大
(kth.cpp/c/pas)
時間限制:1s
內存限制:256MB
【問題描述】
一個區間的價值定義為該區間中的最大值減最小值
給定 n 個數,求所有區間價值中,第 k 大值為多少。
【輸入】
輸入文件名為 kth.in。
第 1 行兩個數 n、k(k<=n*(n-1)/2)
第 2 行 n 個數,每個數<=10
9
【輸出】
輸出文件名為 kth.out。
輸出區間價值的第 k 大值。
【輸入輸出樣例】
kth.in kth.out
32
213
2
【樣例解釋】
[l,r]表示第 l 個數到第 r 個數組成的區間的價值
[1,1]=0 [1,2]=1 [1,3]=2
[2,2]=0 [2,3]=2
[3,3]=0
【數據說明】
對於 30%的數據,n=500
對於 60%的數據,n<=5000
對於 100%的數據,n<=400000
更多資 詢 :北京信息學竇老師 QQ3377089232
3.武器分配
(submax.cpp/c/pas)
3.武器分配
(submax.cpp/c/pas)
時間限制:1s
內存限制:256MB
【問題描述】
有 n 個堡壘排成一排構成了一條防禦線。 現在需要將 n 個武器放入這 n 個堡壘中, 每個
堡壘放一個,每個武器有攻擊力和戰場貢獻值兩個屬性。
由於這 n 個武器都不是人為操控的, 所以會對其某半徑內所有單位進行攻擊, 而這就導
致某些堡壘的互相攻擊。現在發現第 i 個堡壘會和第 j 個堡壘互相攻擊當且僅當|i-j|<=r,
且攻擊力較低的武器和他所在的堡壘會破損。
現在你需要給出一種武器分配方案使得未破損武器的戰場貢獻值總和最大。 為了方便你
只需輸出戰場貢獻值總和的最大值即可。
【輸入】
輸入文件名為submax.in。
第一行一個數 T(<=10),表示數據組數
對於每一組數據:
第一行兩個數 n,r
第二行 n 個數,表示 1~n 號武器的攻擊力
第三行 n 個數,表示 1~n 號武器的戰場貢獻值
【輸出】
輸出文件名為submax.out。
對於每組數據輸出一個數,表示答案
【輸入輸出樣例】
submax.in submax.out
1
4 2
1 2 3 4
1 2 3 4
7
【數據範圍】
對於 30%的數據:n<=10
對於 50%的數據,n<=16
對於 100%的數據,n<=5000,武器攻擊力<=100000 且兩兩不同,武器的戰場貢獻值
<=100000,r<n
更多資 詢 :北京信息學竇老師 QQ3377089232
題面

10.13NOIP模擬題