Codeforces_1186——题解及AC代码by_Hile

题目链接:https://codeforces.com/contest/1186

A. Vus the Cossack and a Contest(600)

此题不会

B. NULL

此题没了

C. Vus the Cossack and Strings(1800)

题意:给定01串a与b,保证b的长度不大于a,求a中与b等长的所有连续子串中与b不同的位数为偶数的子串个数,即

Σ ( Σ ( a . s u b s t r [ i ] b [ i ] ) ) \Sigma(\Sigma(a.substr[i]\oplus b[i]))
解析:由于a和b都为01串,则当其相同数字个数之差为偶数时,无论如何排列,其不同的位数恒为偶数(不同排列可以看作多次交换,交换一次只能改变两个位置的数,由(n+2k)&1==n1得到结论)。

#include<bits/stdc++.h>
using namespace std;
int sum[1000010],d,ans;
string a,b;
int main()
{
    ios::sync_with_stdio(false);
    cin>>a>>b;
    for(int i=1;i<=a.size();i++){sum[i]=sum[i-1]+a[i-1]-'0';}
    for(int i=0;i<b.size();i++)d+=b[i]-'0';
    for(int i=b.size();i<=a.size();i++)ans+=((sum[i]-sum[i-b.size()])%2==d%2);
    cout<<ans;
}

D. Vus the Cossack and Numbers(1600)

题意:给定n个实数a1,a2…ai,我们对每个数都可以进行向上取整或向下取整的操作。现在,要使所有数操作之后的结果之和为零(题目保证结果存在),求出操作后的数列。

解析:既然题目保证有解,我们就可以使用贪心的思想,先将所有数都向下取整后求出和为S,然后遍历整个数组,每向上取整一次就等价于S++(此处要注意S为整数的情况),当S为零时结束,输出结果。

#include<bits/stdc++.h>
int n;
double a[100010],s=0;
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)scanf("%lf",&a[i]),s+=(int)(a[i]<0&&a[i]!=(int)a[i]?(a[i]-1):a[i]);
    for(int i=0;i<n;i++)
    {
        if(a[i]==(int)a[i]){printf("%d\n",(int)a[i]);continue;}
        if(s)
        {
            if(a[i]<0)printf("%d\n",(int)a[i]),s++;
            else printf("%d\n",(int)(a[i]+1)),s++;
        }
        else printf("%d\n",(int)(a[i]<0?(a[i]-1):a[i]));
    }
}

E. Vus the Cossack and a Field(2500)

题意:给定大小为n*m的01矩阵M和变换S: M [ M M M M ] ( M M 01 ) M\to\left[ \begin{matrix} M & \overline{M} \\ \overline{M} & M \end{matrix} \right](\overline{M}表示将M中所有01翻转后的矩阵)
对M进行无限次变换S后。给出q个询问,每个询问包含四个数x1、y1、x2、y2,分别是矩阵左上角和右下角的坐标。对于每次询问,求出所问矩形中的所有元素之和。

解析:首先,根据变换S不难得出, M M + M \overline{M} = n m n*m ,也就是说,我们可以通过以下公式预处理出进行一次变换后的2n*2m矩阵的二维前缀和,即
s u m [ i ] [ j ] = s u m [ i 1 ] [ j ] + s u m [ i ] [ j 1 ] s u m [ i 1 ] [ j 1 ] + a [ i ] [ j ] sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j]
(其实就是容斥定理,由此可以类比出k维前缀和的公式(呜呜呜不会画图)。)
同样利用前缀和的思想,我们可以把从 ( x 1 , y 1 ) (x1,y1) ( x 2 , y 2 ) (x2,y2) 的和转化为
s u m [ x 2 ] [ y 2 ] + s u m [ x 1 1 ] [ y 1 1 ] s u m [ x 1 1 ] [ y 2 ] s u m [ x 2 ] [ y 1 1 ] sum[x2][y2]+sum[x1-1][y1-1]-sum[x1-1][y2]-sum[x2][y1-1]
对于每个 s u m [ i ] [ j ] sum[i][j] ,考虑其和2n*2m的数量关系,经过稍微麻烦的的分类讨论就能做出来啦~

(看了橙名大佬lintoto的大佬的ac代码,学到了一些神奇的预处理和位运算的方法,%%%)
(还是因为爆longlong而wa了好几发QAQ)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2010;
int n,m,Q,s[N][N];
char str[N];
ll calc(ll x,ll y)
{
    ll ret=(x*y-(x%n)*(y%m))/2;
    ll t=(x/n)^(y/m),num=0;
    while(t)num+=t&1,t>>=1;
    if(num&1)ret+=(x%n)*(y%m)-s[x%n][y%m];else ret+=s[x%n][y%m];
    return ret;
}
int main()
{
    scanf("%d%d%d",&n,&m,&Q);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",str+1);
        for(int j=1;j<=m;j++)s[i][j]=s[i+n][j+m]=str[j]-'0',s[i+n][j]=s[i][j+m]=s[i][j]^1;
    }
    n<<=1,m<<=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
    while(Q--)
    {
        ll a,b,c,d;scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
        printf("%lld\n",calc(c,d)+calc(a-1,b-1)-calc(a-1,d)-calc(c,b-1));
    }
}

F. Vus the Cossack and a Graph(2300)

题意:咕咕咕

发布了7 篇原创文章 · 获赞 10 · 访问量 439

猜你喜欢

转载自blog.csdn.net/weixin_44700995/article/details/94822406