Codeforces Educational Codeforces Round 48

模拟题真实难..呕

A.Death Note

题意,给你一本书和一个m,每页上可以写m个名字,写满就要翻页。再给你n个数字,第i天要写ai个名字。问你每天各要翻几页?

模拟题,没啥好说的。

B.Segment Occurrences

题意,给你两个字符串s和t。问在s的[l,r]中t出现的次数是多少。又是模拟题,为了方便起见,我们考虑从s中的i位置开始接下来的连续的一串字母是不是和t相同,如果是,说明这个位置开始是可以出现t的。我们对它做一下前缀和,就可以轻松应付大量的询问次数。

对于询问[l,r],我们将r处理为r’=r-t.length()+1。然后如果此时r’已经到l的左边,那么无解,否则ans=sum[r’]-sum[l-1]。

#include<iostream>
#include<cstring>
using namespace std;

#define MAX(x,y) (((x)>(y))?(x):(y))
string s,t;
int lens,lent,q;
int num[6005];
int main()
{
    cin>>lens>>lent>>q;
    cin>>s>>t;
    memset(num,0,sizeof(num));
    for(int i=0;i<=lens-lent;i++)
    {
        int flag=0;
        for(int j=0;j<lent;j++)if(s[i+j]!=t[j])flag=1;
        num[i+1]=num[i];
        if(!flag)num[i+1]++;
    }
    for(int i=0;i<q;i++)
    {
        int l,r;
        cin>>l>>r;
        r=r-lent+1;
        if(r<l)
        {
            cout<<0<<endl;
            continue;
         } 
        cout<<num[r]-num[l-1]<<endl;
    }
    return 0;
 } 

C.天下第一垃圾模拟题

看到小标题了吗?好,我们看下一题。

D. Vasya And The Matrix

给你一个n*m的矩阵。然后分别给你每行和每列的xor,问你这个矩阵是什么。如不存在输出NO。

扫描二维码关注公众号,回复: 4030179 查看本文章

我看到第一反应是全部填0,然后右边和下边填对应的数,最后确定右下角的格子是否存在这样的数。但是我没办法证明这个算法是否正确,所以我没这么做。听说是可以过的,希望各位大佬教我证明。

我这边因为看到xor,所以想到拆位。我们考虑一个base=2^a,穷举base直到超出范围,分别统计每一位每个矩阵的格子里为1还是0,最后加起来得到最终结果。

这样说有点抽象,我们举个例子。

比方说题目是这样(x是要求的数,边上的数字是异或和)
□ 5 3 13
2 x x x
9 x x x

转换成二进制

□□□□ 0101 0011 1101
0010 xxxx xxxx xxxx
1001 xxxx xxxx xxxx

我们先拆base=2^0=1

□ 1 1 1
0 x x x
1 x x x

显然,对于异或和为1的某行(或某列),其中的1的个数应该是奇数,反之为偶数个,所以横着的1的个数和竖着的1的个数的奇偶应该相同。否则如果横着是奇数,竖着是偶数,那么我们用上面的推论,可以分别得出拆位矩阵中1的个数既是奇数个,又是偶数个,矛盾,vice verse。

当奇偶相同以后,我们用以下的策略填:

1.先找行1和列1的交汇格填1,这样能解决同样多个行1和列1

□ 1 1 1
0 x x x
1 1 x x

2.由于上面的推论,一定剩下偶数个行1(或列1),那么把它们填在同列(同行),因为偶数个所以不会影响所填的列(行)的状态。

□ 1 1 1
0 x 1 1
1 1 x x

3.其余位置填0

□ 1 1 1
0 0 1 1
1 1 0 0

最后把表更新进答案就完事了

#include<iostream>
#include<cstring>
using namespace std;

#define LL long long
LL ans[105][105];
int row[105],col[105];
LL a[105],b[105];
LL n,m;
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=m;i++)cin>>b[i];
    memset(ans,0,sizeof(ans));
    long long base=1;
    while(base<1e9+7)
    {
        memset(row,0,sizeof(row));
        memset(col,0,sizeof(col));
        int cntr=0,cntc=0;
        for(int i=1;i<=n;i++)if(a[i]&base)row[i]=1,cntr++;
        for(int i=1;i<=m;i++)if(b[i]&base)col[i]=1,cntc++;
        if((cntr&1)^(cntc&1))break;

        if(cntr>cntc)
        {
            int cnt=cntc;
            int pntr=0,pntc=0;
            while(cnt--)
            {
                pntr++;
                pntc++;
                while(!row[pntr])pntr++;
                while(!col[pntc])pntc++;
                ans[pntr][pntc]+=base;
            }
            cnt=cntr-cntc;
            while(cnt--)
            {
                if(cntc==0)pntc=1;
                pntr++;
                while(!row[pntr])pntr++;
                ans[pntr][pntc]+=base;
            }
        }
        else
        {
            int cnt=cntr;
            int pntr=0,pntc=0;
            while(cnt--)
            {
                pntr++;
                pntc++;
                while(!row[pntr])pntr++;
                while(!col[pntc])pntc++;
                ans[pntr][pntc]+=base;
            }
            cnt=cntc-cntr;
            while(cnt--)
            {
                if(cntr==0)pntr=1;
                pntc++;
                while(!col[pntc])pntc++;
                ans[pntr][pntc]+=base;
            }
        }

        base=base*2;
    }
    if(base<1e9+7)cout<<"NO"<<endl;
    else
    {
        cout<<"YES"<<endl;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)cout<<ans[i][j]<<" ";
            cout<<endl;
        }
    }
}

补充对于填0方案的证明:

首先,我们不妨设两边分别为a1,a2…an;b1,b2…bm。

首先,如果这里写图片描述,那么答案一定是NO。
因为a1⊕a2⊕…⊕an和b1⊕b2⊕…⊕bm分别是矩阵中所有元素的异或和。如果他们不相等,那么显然是矛盾的。于是我们得到:

a1⊕a2⊕…⊕an⊕b1⊕b2⊕…⊕bm=0 (1)

接下来再看题目,对于题目:

□□ b1 b2 … bm
a1
a2

an

我们除了matrix[1][1]之外按照以下的方案填写(因为排版,所有0用00表示):

□□ b1 b2 … bm
a1 xx b2 … bm
a2 a2 00 … 00
… … … … …
an an 00 … 00

最后只剩下matrix[1][1]没有解决,我们希望构造出这一个解。由题意,不难得出:

matrix[1][1]⊕a2⊕…⊕an=b1 (2)

matrix[1][1]⊕b2⊕…⊕bm=a2 (3)

移项后得到:

matrix[1][1]=a2⊕…⊕an⊕b1 (4)

matrix[1][1]=b2⊕…⊕bm⊕a2 (5)

好的,那么接下来这边只需要证明(4)(5)的右边相等即可。此时我们对
a1⊕a2⊕…⊕an⊕b1⊕b2⊕…⊕bm=0(1)进行变形,得到:

a2⊕…⊕an⊕b1 = b2⊕…⊕bm⊕a2 = matrix[1][1]

那么说明这样的matrix[1][1]是存在且唯一的,于是证明完毕。

E.Rest in the Shades

看似很复杂的一道题,其实还是模拟。。

题意是给你一个匀速移动的光源,再给你一些屏障(在同一条线上),询问一些点无法被光源照射的时长。这道题因为有两组大型数据(屏障,点),所以必定是对其中一个进行预处理。那么我们不难想到,不妨将询问点作为光源,反向处理,其实本质是一样的。

为了提高运行效率,我们再处理一下前缀和,用二分加速一下(好像不二分的话会TLE),花上大量的时间去模拟。叮!AC!

特别提醒一下。我打二分的时候一直忘记要把上下界定在答案外面,这边我调了好久才调对,所以略作提醒。此外,用&判断奇偶性的时候,记住&的优先级是低于==的,所以判断为偶数的时候要加括号。

#include<iostream>
#include<cmath>
using namespace std;

const double EPS=1e-6;
double s,a,b,t,l,r;
long long n,q,tmp;
double sum[400005],fence[400005],x,y;

void read(long long &x)
{
    x=0;long long f=-1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return;
}

bool equ(double a,double b)
{
    if(fabs(a-b)<EPS)return 1;
    return 0;
}

int findfi(double x)
{
    int ll=0,rr=2*n+1;
    while(ll<rr-1)
    {
        int mid=(ll+rr)>>1;
        if(fence[mid]>x)rr=mid;
        else ll=mid;
    }
    return rr;
}

int finden(double x)
{
    int ll=0,rr=2*n+1;
    while(ll<rr-1)
    {
        int mid=(ll+rr)>>1;
        if(fence[mid]>x)rr=mid;
        else ll=mid;
    }
    return ll;
}

int main()
{
    cin>>s>>a>>b;
    t=b-a;

    read(n);
    sum[0]=0;
    for(int i=1;i<=2*n;i++)
    {
        read(tmp);
        fence[i]=tmp;
        sum[i]=sum[i-1];
        if(i%2==0)sum[i]+=fence[i]-fence[i-1];
     } 
     fence[0]=0;fence[2*n+1]=1e10+9;

     read(q);
     for(int i=0;i<q;i++)
     {
        read(tmp);x=tmp;
        read(tmp);y=tmp;
        if(equ(x,a))
        {
            l=x;
            r=(b*y-x*s)/(y-s);
         }
         else if(equ(x,b))
         {
            r=x;
            l=(a*y-x*s)/(y-s);
         }
         else
         {
            l=(a*y-x*s)/(y-s);
            r=(b*y-x*s)/(y-s);
         }
         double zeroo=0;
         if(l>fence[2*n]||r<fence[1])printf("%.10f\n",zeroo);
         else
         {
             int fi=findfi(l);
             int en=finden(r);
             double whole=r-l,partt=sum[en]-sum[fi];
             if(en<fi)
             {
                if(en&1)partt=whole;
                else partt=0;
             }
             else
             {
                 if(fi%2==0)
                 {
                    double pre=fence[fi];
                    partt+=pre-l;
                 }
                 if(en&1)
                 {
                    double post=fence[en];
                    partt+=r-post;
                 }
             } 
             double rat=(partt/whole)*t;
             printf("%.10f\n",rat);
         }
     }

}

猜你喜欢

转载自blog.csdn.net/qq_42778110/article/details/81411072