比赛链接
密码: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 0
r+=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;
}