10.13NOIP模拟题

/*
容斥原理
考虑到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
题面

 

posted @ 2018-10-14 17:27  安月冷  阅读(206)  评论(0编辑  收藏  举报