天天看点

补几道题

一直忙着复习,所以好久好久没写题解了。

暑假集训开始了,开始写题解吧,顺便有自己的一个计划,会在博客中体现的:

cf #240 div2 D

D. Mashmokh and ACM

Mashmokh’s boss, Bimokh, didn’t like Mashmokh. So he fired him. Mashmokh decided to go to university and participate in ACM instead of finding a new job. He wants to become a member of Bamokh’s team. In order to join he was given some programming tasks and one week to solve them. Mashmokh is not a very experienced programmer. Actually he is not a programmer at all. So he wasn’t able to solve them. That’s why he asked you to help him with these tasks. One of these tasks is the following.

A sequence of l integers b1, b2, …, bl (1 ≤ b1 ≤ b2 ≤ … ≤ bl ≤ n) is called good if each number divides (without a remainder) by the next number in the sequence. More formally for all i (1 ≤ i ≤ l - 1).

Given n and k find the number of good sequences of length k. As the answer can be rather large print it modulo 1000000007 (109 + 7).

Input

The first line of input contains two space-separated integers n, k (1 ≤ n, k ≤ 2000).

Output

Output a single integer — the number of good sequences of length k modulo 1000000007 (109 + 7).

input

3 2

output

5

题意: 就是说输入n,k; 问你在1-n中 长度为k的有效序列有多少个, 有效序列的定义 就是 非递减序列,1<=ai<=n 且ai+1 % ai ==0, 也就是每一个序列中的数都是前一个的整数倍。

分析: 这种题目需要我们慢慢推理: 不能急也不能慌,感觉上是肯定能做的。

首先 这个序列 自然是与n息息相关, 自然和长度k 也有关系。

而且 n 和n-1 的序列必然也是 有关系的, 由此我们细想一会儿不难想到是状态的转移,既然想到这方面必然就得思考怎么创建dp与转移方程。

不妨设 dp[i ][ j ]代表 以i为结尾的 长度为j的最大值; 那么想想若是i,j+1 呢? 我们可以在原来的长度为j的后面加一个i即可, 说明 dp[i][j+1] >=dp[i][j]。 那么i 的整数倍 也是如此:dp[i*k][j+1]>dp[i][j];

不难得到结果;

int main()
{
    //freopen("1.txt","r",stdin);
    int n,k;
    scanf("%d %d",&n,&k);
    for(int i=1;i<=n;i++) //所有长度为1,以i结尾的都一种
        dp[i][1]=1;
    for(int j=1;j<k;j++){
       for(int i=1;i<=n;i++){
         if(dp[i][j])
           for(int len=i;len<=n;len+=i){
               //长度为j+1,以 i的倍数   结尾的必然包含长度为j 以i结尾的种数
               // 因为在后面加上一个i的倍数 即可
               dp[len][j+1]+=dp[i][j],dp[len][j+1]%=MOD;

           }
       }
    }
    int ans=0;
    for(int i=1;i<=n;i++){  //所有长度为k的,以1-n结尾的
        ans+=dp[i][k],ans%=MOD;
    }
    printf("%d\n",ans);
    return 0;
}           

一场GYM 试试手而已,最后还是没有AK

2016 Al-Baath University Training Camp Contest-1 I. March Rain

题意:

由一串序列1-n来表示屋顶,在这个屋顶上会给你洞,然后你最多使用k块板子, 每一块板子的长度都可以自由更改,可以不同,然后问板子中 最长的板子 最小值是多少?

最小化最大值,咋一想觉得是贪心,但是最后20+分钟想了一会儿贪心觉得想不出来, 往正解上想到了,但是并没有时间敲and debug了。 其实二分也可以看成一种贪心, 我们只需要二分板子的长度(1-1e9),然后判断在这个长度下,板子够不够用即可

using namespace std;
int pos[1000005];
int p[1000005];
int work(int n,int len){
    int cnt=0;
    int ans=0;
    for(int i=1;i<=n;i++){
        if(pos[i]>cnt){
//          printf("dong =%d ",pos[i]);
            ans++;
            cnt=pos[i]+len-1;
//          printf("%d %d\n",cnt,pos[i]);
        }
    }
    return ans;
}
int main(){
    int t;
    //freopen("1.txt","r",stdin);
    scanf("%d",&t);
    while(t--){
        int n,k;
        scanf("%d %d",&n,&k);
        for(int i=1;i<=n;i++)
            scanf("%d",&pos[i]);
        int l=1;
        int r=pos[n];
        while(l<r){
            int mid=(l+r)/2; //现在长度为mid
//          printf("%d %d %d\n",l,r,work(n,mid));
            if(work(n,mid)> k){  //长度不够,需要>cnt块
                l=mid+1;
            }
            else
                r=mid;
        }
        printf("%d\n",l);
    }
return 0;
}           

J X and Beasts

这个题就是一个最大递增子序列问题,不是最长而是最大,由于n*n可以过,就随便写了写

using namespace std;
int f[1000005];
int x[105],y[105];
void work(){
    mem(f);
    for(int i=2;i<=1000000;i*=2){
        for(int j=1;j*i<=1000000;j++){
            f[i*j]++;
        }
    }
//  for(int i=1;i<=100;i++){
//      printf("%d %d\n",i,f[i]);
//  }
}
int dp[105];
int main(){
    //freopen("1.txt","r",stdin);
    work();
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        int sum=0;
        scanf("%d",&n);
        int pre=0;
        for(int i=1;i<=n;i++){
             scanf("%d",&x[i]);
             //x[i]=f[x[i]];
        }
        for(int i=1;i<=n;i++){
            int maxn=0;
            for(int j=i-1;j>=1;j--){
                if(x[i]>x[j]){
                    maxn=max(maxn,dp[j]);
                }
            }
            dp[i]=f[x[i]]+maxn;

        }
        for(int i=1;i<=n;i++)
            sum=max(sum,dp[i]);
        printf("%d\n",sum);
    }
return 0;
}