Codeforces Round #493 (Div. 1)

A : 模拟
B : 打表
C : 容斥+反演+推式子
D : Unfinished
E : Unfinished
这些题是赛后刷的,因为当时并不知道有这场比赛,就算知道可能也因为网络或者时间问题打不了吧…
D和E看起来没什么人过,估计很难,先丢了。


A. Convert to Ones

考虑一个串,连续的0有多少段,显然一次取反操作最多使段数减一,一次翻转也至多使段数减一。那就挑取反和翻转中代价小的一直做就好了。注意最后只剩1个连续的0段的时候只能取反。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define cmax(_i,_j) ((_i)<(_j)?(_i)=(_j):0)
#define cmin(_i,_j) ((_i)>(_j)?(_i)=(_j):0)
#define N 300005
using namespace std;
namespace runzhe2000
{
    int n, x, y;
    char s[N];
    void main()
    {
        scanf("%d%d%d%s",&n,&x,&y,s+1); int cnt = 0;
        for(int i = 1; i <= n; i++) if(s[i] == '0' && s[i-1] != '0') cnt++;
        if(!cnt){printf("0\n");return;}
        if(x >= y) printf("%I64d\n",1ll*y*cnt);
        else printf("%I64d\n",1ll*x*(cnt-1)+y);
    }
}
int main()
{
    runzhe2000::main();
}
B. Roman Digits

这题我不是太清楚怎么做…总之打表打出来发现从n=11开始,答案是一个公差为49的等差数列。啊不会证。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define cmax(_i,_j) ((_i)<(_j)?(_i)=(_j):0)
#define cmin(_i,_j) ((_i)>(_j)?(_i)=(_j):0)
using namespace std;
namespace runzhe2000
{
    int f[12]={0,   4,   10,   20,   35,   56,   83,  116,  155,  198,  244,  292};
    void main()
    {
        int n; scanf("%d",&n);
        if(n <= 11) printf("%d\n",f[n]);
        else printf("%I64d\n",f[11]+(n-11)*49ll);
    }
}
int main()
{
    runzhe2000::main();
}
C. Sky Full of Stars

首先想法肯定是容斥。设 f[i][j] f [ i ] [ j ] 表示至少有 i i 行, j 列颜色一样的方案数。设 g[i][j] g [ i ] [ j ] 表示恰有 i i 行, j 列颜色一样的方案数。

然后它们会有这样的关系 :

f[i][j]=i=inj=jng[i][j](ii)(jj) f [ i ] [ j ] = ∑ i ′ = i n ∑ j ′ = j n g [ i ′ ] [ j ′ ] ( i ′ i ) ( j ′ j )

对这个东西用类似二项式反演的东西可以推(猜)出(测)出它的反演应该是这样的:

g[i][j]=i=inj=jnf[i][j](ii)(jj)(1)ii+jj g [ i ] [ j ] = ∑ i ′ = i n ∑ j ′ = j n f [ i ′ ] [ j ′ ] ( i ′ i ) ( j ′ j ) ( − 1 ) i − i ′ + j − j ′

如果不太确定,可以打个表发现上面这个式子是对的,然后我们要求出所有的 g g ,至少就会是平方级别的,实际上只要求 g[0][0] ,然后拿 3n2 3 n 2 减一下就好了。那么我们现在只要求一个东西啦。

g[0][0]=i=0nj=0nf[i][j](1)i+j g [ 0 ] [ 0 ] = ∑ i = 0 n ∑ j = 0 n f [ i ] [ j ] ( − 1 ) i + j

其中

f[i][j]=3(ni)(nj)+1(ni)(nj) f [ i ] [ j ] = 3 ( n − i ) ( n − j ) + 1 ( n i ) ( n j ) ,若 i,j i , j 都不为 0 0
f[i][j]=3n(ni)+1(ni) ,若 i i 0 j j 不为0。对称的 i i 不为0 j j 0类似。
f[i][j]=3n2 f [ i ] [ j ] = 3 n 2 ,若 i,j i , j 都为 0 0

后两种情况分别能在O(n) O(1) O ( 1 ) 时间内做完,考虑第一种,也就是

i=1nj=1n3(ni)(nj)+1(ni)(nj)(1)i+j ∑ i = 1 n ∑ j = 1 n 3 ( n − i ) ( n − j ) + 1 ( n i ) ( n j ) ( − 1 ) i + j

=3i=1n(ni)(1)ij=1n(3ni)nj(nj)(1)j = 3 ∑ i = 1 n ( n i ) ( − 1 ) i ∑ j = 1 n ( 3 n − i ) n − j ( n j ) ( − 1 ) j

=3i=1n(ni)(1)i[(3ni1)n3n(ni)] = 3 ∑ i = 1 n ( n i ) ( − 1 ) i [ ( 3 n − i − 1 ) n − 3 n ( n − i ) ]

然后就OK了。

#include<bits/stdc++.h>
#define N 1000005
#define MOD 998244353
using namespace std;
typedef long long ll;
int fac[N], inv[N];
int comb(int a, int b){return 1ll*fac[a]*inv[b]%MOD*inv[a-b]%MOD;}
int fpow(int a, ll b)
{
    int r = 1;
    for(;b;b>>=1)
    {
        if(b&1)r=1ll*r*a%MOD;
        a=1ll*a*a%MOD;
    }
    return r;
}
int main()
{   
    int n; scanf("%d",&n);
    fac[0] = 1; for(int i = 1; i <= n; i++) fac[i] = 1ll * fac[i-1] * i % MOD;
    inv[1] = 1; for(int i = 2; i <= n; i++) inv[i] = 1ll*(MOD-MOD/i)*inv[MOD%i]%MOD;
    inv[0] = 1; for(int i = 1; i <= n; i++) inv[i] = 1ll*inv[i-1]*inv[i]%MOD;
    int ans = 0;
    ans += fpow(3,1ll*n*n); // f 0 0
    for(int i = 1; i <= n; i++) // f 0 x
        (ans += (i%2?MOD-1ll:1ll) * fpow(3,i) % MOD * fpow(3,1ll*(n-i)*n) % MOD * comb(n, i) % MOD * 2 % MOD) %= MOD;
    for(int i = 1; i <= n; i++) // f x x
        (ans += 3ll * comb(n,i) % MOD * (i%2?MOD-1:1) % MOD * (fpow(fpow(3,n-i)-1, n) - fpow(3, 1ll*n*(n-i)) + MOD) % MOD) %= MOD;
    printf("%d\n",(fpow(3,1ll*n*n)-ans+MOD)%MOD);

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值