2017 12 3 个人赛 题目记录 小dp

来源:互联网 发布:王者荣耀用户数据分析 编辑:程序博客网 时间:2024/06/05 20:27

比赛链接
密码:shewoqishui
A:
Penny is a terrible waitress and even worse actress, however recently she applied for a role in an upcoming TV series. Even though she thought she had no chance, she was called for an audition. She was very happy about it until she found out that her character in this new series will be a studious, high IQ girl named Megan. Producer told her that to get the role of Megan she had to prove that her mind can handle a bit of mathematics and reasoning. If she passed the test then she will be given the role of Megan. The test was as follow.

The people (Boys and Girls) who came for audition are standing in a line in a random order. Producer has to select exactly K boys for the show. So he asks Penny to tell how many ways can he select two numbers i and j such that the number of boys standing between these (including I and j) indexes is exactly K.

Penny desperately needs this role. Everybody knows that Penny is not a very smart and requests you to help her.

Input

First line contains T – The number of test cases.

Next line contains space separated N and K.

N – The total number of boys and girls who came to audition.

K – The number of the boys who must be there between each (i, j) pair.

Next line contains a non-empty string consisting of ‘1’ and ‘0’.

1 represents Boy.

0 represents Girl.

Output

The number of (i, j) pairs such that the number of boys between index i and j, both inclusive is equal to K.

Constraints

1<=T<=10

1<=N<=10^6

0<=K<=10^6

Example

Input:
3

4 1

0101

5 2

01010

5 4

01010

Output:
6
4
0

求区间内1的个数正好等于k的区间有多少对(包含单点区间)?

#include <bits/stdc++.h>using namespace std;const int maxn = 1e6+7;char str[maxn];int pre[maxn];int main(){    int t,tot,n,k,i;    cin>>t;    while(t--)    {        scanf("%d%d",&n,&k);        scanf("%s",str);        memset(pre,0,sizeof(pre));        long long r;        r = 0LL;        tot = 0;        if(k==0)        {            for(i=0;str[i];i++)            {                if(str[i]=='1')                    tot =0 ;                else tot++;                r+=tot;            }            cout<<r<<endl;            continue;        }        pre[0]++;        for(i=0;str[i];i++)        {            tot+=(str[i]-'0');            pre[tot]++;            if(tot>=k)                r+=pre[tot-k];        }        cout<<r<<endl;    }    return 0;}
以样例一为例0101这个区间首先pre[0] = 1,是初始化,也是为了和之后的所有计算保持一致,对于tot 四次计算值分别为 0 1 1 2用来表示到当前区间为止1的个数和比如计算下标0时,tot=0;计算下标1时,tot=1,这样正好大于等于1,此时pre 2 0 0 0r+=pre[0],表示的是(1,1)和(01)这两个区间,其中(11)这个区间加的是初始化的那个1,因为所有满足tot>=k的都会包含本身(下标)这个区间,计算到下标2时,这时候tot还是等于1,此时加的tot-k表示的是上一个满足tot>=k的区间的tot值,而pre存的正是除了当前所访问的下标之外,之前的下标可以和当前下标有几种组合方法,这样考虑正好可以避免重复,而且完美的满足了区间内1的个数正好等于k,再说样例,计算到下标2时,这时候上一个满足条件的区间可以提供给该区间的组合数为pre[0] = 2,也就是加上了(0,2)和(1,2)这两个区间,此时pre[1]一共加了两次,其中在下标为1时加1代表的含义类似于初始化pre[0]=1,代表在跟之后再出现的1组合时,去掉当前所出现的1,这个主要是因为题目必须要满足1的个数正好等于k的原因以后分析同上...最后得出的pre数组为 2 2 1 0相当于把tot的出现值进行了一次桶排确实很奇妙的一道题目

C Domino Principle CodeForces - 56E
同样是一道小dp
比赛中一直写的双重for循环,导致超时,当时感觉如果写dp的话有一种情况是算不对的,赛后仔细分析了一下,根据因果关系当时分析错了,所以加一个dp数组维护一下每一块的答案,从后往前推,最后在用一个ans数组桶排异一下(非必需),其实就是把我之前写的两个for循环合在一起就是最终的结果啦

#include <iostream>#include<bits/stdc++.h>using namespace std;const int maxn = 2e6;struct node{    int x,h;    int i;    int ans;    int pre;}a[maxn];int d[maxn],ans[maxn];int cmp1(node a,node b){    return a.x<b.x;}int cmp2(node a,node b){    return a.i<b.i;}int main(){     int n;     cin>>n;    for(int i=1;i<=n;i++)    {        scanf("%d%d",&a[i].x,&a[i].h);        a[i].i = i;         a[i].ans = 1;         a[i].pre = 0;         d[i] =1;    }    sort(a+1,a+1+n,cmp1);    a[n].ans =1;    for(int i=n;i>=1;i--)    {        int x = a[i].x;        int h = a[i].h;        int ax = x+h-1;        int j = i+1;        while(j<=n&&x+h-1>=a[j].x)        {            j+=d[j];            // a[i].ans++;        }        d[i] = j-i;        ans[a[i].i] =d[i];    }//    //a[n].ans = 1;//    for(int i=n;i>=1;i--)//    {//        int x = a[i-1].x;//        int h = a[i-1].h;//        int xx = a[i].x;////        if(x+1<=xx&&xx<=x+h-1)////        {////            a[i-1].ans += (a[i].ans);////        }////        else////        {////            a[i-1].ans = 1;////            cout<<"i-1 "<<i-1<<endl;////        }//        a[a[i].pre].ans += (a[i].ans);//        d[a[i].i] = a[i].ans;////    }//    //sort(a+1,a+1+n,cmp2);    for(int i=1;i<=n;i++)    {        if(i==1)printf("%d",ans[i]);        else printf(" %d",ans[i]);    }    return 0;}

G 很简单的一个排列组合,推出公式,用一下容斥消一下元就可以推出最后的结果,特别注意sum==n并不一定就是1,
当时什么公式都不记得了,所以就手工推算的,然后消元

#include <iostream>#include<bits/stdc++.h>using namespace std;const int maxn = 2e6;long long j[maxn];int a[maxn];int main(){    int n,m,h;    cin>>n>>m>>h;    int sum =0 ;    for(int i=1; i<=m; i++)    {        cin>>a[i];        sum+=a[i];    }    if (sum<n)cout<<"-1"<<endl;    //else if(sum==n) cout<<"1"<<endl;    else    {        long long aa,bb,cc,dd;        aa = sum-1;        bb = n-1;        dd = a[h]-1;        double a1=1,a2=1;        for(int i=aa-dd-bb+1; i<=aa-dd; i++)        {            a1*=i;        }        for(int i=aa-bb+1; i<=aa; i++)        {            a2*=i;        }        double ans = a1*1.0/a2;        cout<<1.0-ans<<endl;    }    return 0;}
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 心脏办膜关闭不全怎么办 9个月胎儿脑积水怎么办 怀孕三个月胎盘低置怎么办 怀孕第一个月打针了怎么办 唐氏筛查神经管缺陷高风险怎么办 门诊处方笺丢了怎么办 孕中期睡觉手麻怎么办 怀孕2个月了没胎心胎芽怎么办 怀孕腿疼的厉害怎么办 孕妇老是失眠多梦怎么办 孕妇会失眠多梦怎么办 怀孕5个月睡不着怎么办 6个月孕妇失眠怎么办 彩超脉络丛囊肿怎么办 双侧脉络丛囊肿怎么办 唐筛神经管缺陷高风险怎么办 雌激素低怎么办吃什么东西补 我怀了狗的孩子怎么办 结婚2年不要孩子怎么办 备孕一直没怀孕怎么办 刚生的婴儿打嗝怎么办 小孩40天黄疸高怎么办 婴儿身高长得慢怎么办 四个月的宝宝哭怎么办 孕39周羊水偏多怎么办 孕39周羊水浑浊怎么办 孕晚期羊水过少怎么办 怀孕脐带绕颈一周怎么办 nt检查宝宝趴着怎么办 四维胎儿有问题怎么办 怀孕70天没有胎心怎么办 怀孕20天不想要怎么办 换轮胎胎压监测怎么办 怀孕了吐的厉害该怎么办 怀孕吐完嗓子疼怎么办 怀孕16周不想要怎么办 怀孕四个月胎盘低置怎么办 孕37周胎盘三级怎么办 孕37周胎盘老化怎么办 怀孕22周胎盘1级怎么办 婴儿吃奶粉吐奶怎么办