10.7 test solution.

1.计数 (count.cpp/c/pas)

时间限制:

1s

内存限制:

256MB

【问题描述】

给出 m 个数 a[1],a[2],,a[m]
1n 中有多少数不是 a[1],a[2],,a[m] 的倍数。

【输入】

输入文件名为count.in。
第一行,包含两个整数:n,m
第二行,包含 m 个数,表示a[1],a[2],,a[m]

【输出】

输出文件名为count.out。
输出一行,包含 1 个整数,表示答案

【输入输出样例】

count.incount.out
10 2
2 3
3

【数据说明】

对于60%的数据,1n106
对于另外20%的数据,m=2
对于100%的数据,1n109,0m20,1a[i]109


solution

  • 一眼秒掉的题,就是一个小学生容斥。

  • 还有就是一个小优化,如果 m 个数中存在倍数关系,那就取最小的那个

  • 比如说有两个数,24,如果一个数是 4 的倍数,那他也肯定是 2 的倍数,所以只求 2 的就好了。

code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;

template<typename T>
void input(T &x) {
    x=0; T a=1;
    register char c=getchar();
    for(;c<'0'||c>'9';c=getchar())
        if(c=='-') a=-1;
    for(;c>='0'&&c<='9';c=getchar())
        x=x*10+c-'0';
    x*=a;
    return;
}

#define MAXM 25

ll a[MAXM];

ll gcd(ll a,ll b) {
    return b==0?a:gcd(b,a%b);
}

ll lcm(ll a,ll b) {
    return a/gcd(a,b)*b;
}

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

int main() {
    int n,m;
    input(n),input(m);
    for(int i=0;i<m;i++)
        input(a[i]);
    sort(a,a+m);
    if(a[1]==1) {
        printf("0");
        return 0;
    }
    for(int i=0;i<m;i++) {
        if(a[i]==0) continue;
        for(int j=i+1;j<m;j++)
            if(a[j]%a[i]==0)
                a[j]=0;
    }
    sort(a,a+m,cmp);
    for(int i=0;i<m;i++)
        if(a[i]==0) {
            m=i;
            break;
        }
    //上面就是我说的那个优化,下面是容斥,可能用二进制写有点恶心,不过短小精悍
    int ans=n,sum;
    ll x;
    for(int s=1;s<1<<m;s++) {
        sum=0,x=1;
        for(int i=0;i<m;i++)
            if(s&(1<<i)) {
                x=lcm(x,a[i]);
                sum++;
            }
        if(x>n) continue;
        if(sum&1) ans-=n/x;
        else ans+=n/x;
    }
    printf("%d",ans);
    return 0;
}

2.第k大区间(kth.cpp/c/pas)

时间限制:

1s

内存限制:

256MB

【问题描述】

定义一个长度为奇数的区间的值为其所包含的的元素的中位数。
现给出 n 个数,求将所有长度为奇数的区间的值排序后,第 K 大的值为多少。

【输入】

输入文件名为kth.in。
第一行两个数nk
第二行,n个数。(0每个数<231

【输出】

输出文件名为kth.out。
一个数表示答案。

【输入输出样例】

kth.inkth.out
4 3
3 1 2 4
2

【样例解释】

[l,r]表示区间lr的值
[1,1]3
[2,2]1
[3,3]2
[4,4]4
[1,3]2
[2,4]2

【数据说明】

对于 30% 的数据,1n100
对于 60% 的数据,1n300
对于 80% 的数据,1n1000
对于 100% 的数据,1n100000,k奇数区间的数


solution

  • 求第 k 大这种题一般是二分答案,所以这道题目也是二分

  • 我们二分中位数 mid,然后问题就转换成了怎样快速求出有多少个长度为奇数的区间中位数mid

  • 这里利用了一个特别巧妙的做法

  • 二分之后我们把每个数都重新赋值,mid的数设为1<mid的数设为 0

  • 重新赋值之后,如果一个区间的中位数是mid,那这个区间所有数的和应该是rl+12+1

  • 我们令 sum 为重新赋值之后的前缀和,那二分之后求的也就是满足sum[r]sum[l1]rl+12+1的区间个数

  • 整数的离散性:如果a,bZ,那么ab可以表示为a>b1

  • 根据上面那个东西,我们可以把式子变成 sum[r]sum[l1]>rl+12

  • 然后再把分母乘过去,移项就可以得到 2sum[l1](l1)<2sum[r]r

  • 发现这个式子的两边形式差不多,所以设数组cc[i]=2sum[i]i

  • 然后式子就变成了 c[l1]<c[r],也就是要求满足 c[l1]<c[r]的区间的个数

  • 又因为l1<r ,所以最后求的也就是 c 数组的顺序对个数

  • 最后需要说明的

  • 因为长度为奇数的区间的左右端点l,r奇偶性是相同的,所以l1,r的奇偶性是不同的,所以我们需要分奇偶统计答案

  • 求顺序对我用的是树状数组,会求逆序对的应该可以看懂…

code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;

template<typename T>
void input(T &x) {
    x=0; T a=1;
    register char c=getchar();
    for(;c<'0'||c>'9';c=getchar())
        if(c=='-') a=-1;
    for(;c>='0'&&c<='9';c=getchar())
        x=x*10+c-'0';
    x*=a;
    return;
}

#define MAXN 100010

ll k;
int n,m;
int a[MAXN],b[MAXN];
int t[MAXN];

inline int lowbit(int x) {
    return x&(-x);
}

void modify(int x) {
    for(;x<=m;x+=lowbit(x))
        t[x]++;
    return;
}

int query(int x) {
    int ans=0;
    for(;x;x-=lowbit(x))
        ans+=t[x];
    return ans;
}

int c[MAXN],d[MAXN];

int Lower_bound(int x) {
    int l=1,r=m,mid;
    while(l<r) {
        mid=l+r>>1;
        if(x<=d[mid]) r=mid;
        else l=mid+1;
    }
    return l;
}

ll Judge(int mid) {
    c[0]=0;
    for(int i=1;i<=n;i++)
        c[i]=c[i-1]+(a[i]>=mid);
    for(int i=0;i<=n;i++)
        c[i]=c[i]*2-i,d[i+1]=c[i];
    sort(d+1,d+n+2);
    int rank=1;
    for(int i=2;i<=n+1;i++)
        if(d[i]!=d[rank])
            d[++rank]=d[i];
    m=rank;
    ll ans=0;
    for(int i=0;i<=n;i++)
        c[i]=Lower_bound(c[i]);
    memset(t,0,sizeof(t));
    for(int i=0;i<=n;i++)
        if(i&1) modify(c[i]);
        else ans+=(ll)query(c[i]-1);
    memset(t,0,sizeof(t));
    for(int i=0;i<=n;i++)
        if((i&1)==0) modify(c[i]);
        else ans+=(ll)query(c[i]-1);
    return ans;
}

int main() {
    input(n),input(k);
    for(int i=1;i<=n;i++)
        input(a[i]),b[i]=a[i];
    sort(b+1,b+n+1);
    int rank=1;
    for(int i=2;i<=n;i++)
        if(b[i]!=b[rank])
            b[++rank]=b[i];
    int l=1,r=rank,mid;
    ll result;
    while(l<r) {
        mid=(l+r>>1)+1;
        result=Judge(b[mid]);
        if(result==k) {
            printf("%d\n",b[mid]);
            return 0;
        } else if(result>k) l=mid;
        else r=mid-1;
    }
    printf("%d\n",b[l]);
    return 0;
}

3.区间求和(sum.cpp/c/pas)

时间限制:

2s

内存限制:

256MB

【问题描述】

n 个数,给定一个 k,求所有长度大于等于 k 的区间中前 k 大数的总和。这样就比较简单相信大家都会,所以此题要求当k=1n的总和,即求

k=1ni=1nk+1j=i+k1nk

【输入】

输入文件名为sum.in。
输入五个数n,a1,A,B,Ca1表示第一个数,A,B,C用来生成其余n1个数。a[i]=(a[i1]A+B)modC
1n1000000,0a1,A,B,C1000000000

【输出】

输出文件名为sum.out。
一个数表示答案,最后答案对 1000000007 取模。

【输入输出样例】

sum.insum.out
3 3 1 1 1063

【样例解释】

三个数为 3,4,5
K=1:[1,1]=3,[1,2]=[2,2]=4,[1,3]=[2,3]=[3,3]=5
(表示各个区间在 k=1 时的答案)
K=2:[1,2]=7,[2,3]=[1,3]=9
K=3:[1,3]=12

【数据说明】

对于 30% 的数据,1n100
对于 60% 的数据,1n300
对于 80% 的数据,1n1000
对于 100% 的数据,1n1000000


solution

  • 假设我们已经知道了区间 [l,r] 的答案是 ans,考虑新加入一个数a[r+1]对答案会造成什么影响

  • c[l,r]a[r+1] 的数的个数

  • sum 为区间 [l,r]>a[r+1] 的数的和

  • 那么区间 [l,r+1] 的答案就是 ans+(c+1)a[r+1]+sum

  • f[i] 表示以 i 为右端点的所有的区间的答案之和

  • f[i]=l=1ians[l,i]

  • 把上面推的式子代进去,可以得到

    f[i]=f[i1]+ia[i]+a[j]a[i]ja[j]+a[k]<a[i]ka[i]
  • 最后ans=i=1nf[i]

  • 然后上面那个东西可以用数据结构来维护,这里我选择树状数组

code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;

template<typename T>
void input(T &x) {
    x=0; T a=1;
    register char c=getchar();
    for(;c<'0'||c>'9';c=getchar())
        if(c=='-') a=-1;
    for(;c>='0'&&c<='9';c=getchar())
        x=x*10+c-'0';
    x*=a;
    return;
}

#define mod 1000000007

struct Fenwick_Tree {
    static const int MAXN=1000010;
    ll tree[MAXN];
    int n;
    Fenwick_Tree() {
        memset(tree,0,sizeof(tree));
    }
    int lowbit(int x) {
        return x&(-x);
    }
    void Modify(int k,ll x) {
        for(;k<=n;k+=lowbit(k))
            tree[k]+=x,tree[k]%=mod;
        return;
    }
    int query(int k) {
        int ans=0;
        for(;k;k-=lowbit(k))
            ans+=tree[k],ans%=mod;
        return ans%mod;
    }
    int query(int l,int r) {
        return (query(r)-query(l-1)+mod)%mod;
    }
};

Fenwick_Tree t[2];

#define MAXN Fenwick_Tree::MAXN

ll a[MAXN],b[MAXN];
int Rank;
int f[MAXN];

int Binary_Chop(ll x) {
    int l=1,r=Rank,mid;
    while(l<r) {
        mid=l+r>>1;
        if(x<=b[mid]) r=mid;
        else l=mid+1;
    }
    return l;
}

int main() {
    ll n,A,B,C;
    input(n),input(a[1]),
    input(A),input(B),input(C);
    A%=C,B%=C;
    a[1]%=C;
    for(int i=2;i<=n;i++)
        b[i]=a[i]=(a[i-1]*A+B)%C;
    b[1]=a[1];
    sort(b+1,b+n+1);
    Rank=1;
    for(int i=2;i<=n;i++)
        if(b[i]!=b[Rank])
            b[++Rank]=b[i];
    f[0]=0;
    t[0].n=t[1].n=n;
    ll sum;
    for(int i=1,pos;i<=n;i++) {
        pos=Binary_Chop(a[i]);
        sum=(ll)i*a[i]%mod;
        sum+=(ll)t[0].query(pos)*a[i]%mod;
        sum+=(ll)t[1].query(pos+1,n)%mod;
        f[i]=(ll)(f[i-1]+sum)%mod;
        t[0].Modify(pos,i);
        t[1].Modify(pos,i*a[i]);
    }
    int ans=0;
    for(int i=1;i<=n;i++)
        ans=(ll)(ans+f[i])%mod;
    printf("%d\n",ans%mod);
    return 0;
}
Objectives of this Assignment 1. Declare arrays of different types dynamically. 2. Iterate through arrays, processing all of the elements. 3. Write methods with arrays as parameters and return values In this assignment you will create your own class and write the methods in it. The class you write is called P7_2 and it has four methods that build arrays and four methods that process arrays. All methods should be public and static. Create a project called P7_2 and a class named Main in a file called Main.java, then follow the instructions below exactly: 1.Write a method named createDoubles that builds an array of floating point values that represent the squares of the numbers from start to end, in steps of 0.5, inclusive of both boundaries. The numbers start and end should be readed from the starndard input.See the sample input for details. The method has no parameters and returns an array of doubles. You should calculate the length of this array. 2.Write a method called findLargest that takes an array of doubles as a parameter, and returns a double equal to the largest element in the array. 3.Add a main method with the usual signature that instantiates the Main class and tests its methods as follow: public static void main(String[] args) { // Create arrays double[] doubleArray = createDoubles(); // Test processing System.out.printf("%.1f", findLargest(doubleArray)); } Input Specification: enter two numbers which indicates the start number and the end number. Output Specification: For each case, output the largest number in the created array. Sample Input: 10.0 13.0 Sample Ouput: 169.0
03-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值