【考试记录】Educational Codeforces Round 59 (Rated for Div. 2)

本来准备划水,结果被水淹死了……

$T2:$

定义一个数$x$的数字根$S(x)$为:将其各位数字相加得到一个新数,再将新数的数字和相加直到得到一个个位数,就是该数的数字根。

例如:$S(38)=S(3+8=11)=S(1+1=2)=2$

现在需要求数字根为$x$的从小到大第$k$个数。

$1\leq x\leq 9,k\leq 10^{12}$。

$Solution:$

注意到数字和相加不会改变$x$对$9$取余的值。

那么可以得到:数字根为$x$的数就是满足模$9$的值为$x$的数。

特别地,数字根为$9$的数满足模$9$的值为$0$。

然后一行就可以了。

$Code:$

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>

using namespace std;
#define MAXN 100005
#define MAXM 500005
#define INF 0x7fffffff
#define ll long long

inline ll read(){
    ll x=0,f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar())
        if(c=='-')
            f=-1;
    for(;isdigit(c);c=getchar())
        x=x*10+c-'0';
    return x*f;
}

int main(){
    ll N=read();
    for(ll i=1;i<=N;i++){
        ll k=read(),x=read();
        cout<<x+(k-1)*9<<endl;
    }
    return 0;
}

$T4:$

定义一个$n$次矩阵$A$的$x$次压缩矩阵$B$为:对于任意$i,j$满足$A(i,j)=B(\lceil i/x \rceil,\lceil j/x \rceil)$。

显然对于某些$x$是不存在$x$次压缩矩阵的。

现在给定一个$01$矩阵$A$,求最大的满足$x|n$的能压缩的$x$。

$n\leq 5200$。

$Solution:$

发现压缩的过程就相当于把原矩阵$A$分成若干个$x\times x$的小矩阵,若每个小矩阵内数均相同则$x$次压缩是可行的。

那么暴力算法就是枚举每个$x$再进行$O(n^2)$枚举判断可行性。

考虑优化,枚举$k$的过程不太好优化,我们需要一个快速的办法判断一个小矩阵中的数是否相同。

由于数只有$01$,可以维护二维前缀和,若这个小矩阵内数的和不等于$0$或者$x\times x$则肯定不相同。

时间复杂度为$O(\sum \frac{n^2}{x^2})=O(n^2\times \sum \frac{1}{x^2})=O(n^2)$。

$Code:$

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>

using namespace std;
#define MAXN 5205
#define MAXM 500005
#define INF 0x7fffffff
#define ll long long

inline int read(){
    int x=0,f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar())
        if(c=='-')
            f=-1;
    for(;isdigit(c);c=getchar())
        x=x*10+c-'0';
    return x*f;
}

int N,mp[MAXN][MAXN],sum[MAXN][MAXN];
char str[MAXN];

inline int gets(int x,int y,int xx,int yy){
    return sum[xx][yy]-sum[xx][y]-sum[x][yy]+sum[x][y];
}

bool check(int x){
    for(int i=1;i<=N;i+=x){
        for(int j=1;j<=N;j+=x){
            if(gets(i-1,j-1,i+x-1,j+x-1)!=0 && gets(i-1,j-1,i+x-1,j+x-1)!=x*x)
                return 0;
        }
    }
    return 1;
}

int chg(char ch){
    if(isdigit(ch)) return ch-'0';
    else return ch-'A'+10;
} 

int main(){
    N=read();
    for(int i=1;i<=N;i++){
        scanf("%s",str);
        for(int j=1;j<=N;j+=4){
            int tp=chg(str[j/4]);
            for(int k=0;k<4;k++)
                mp[i][j+k]=(bool)(tp&(1<<(4-k-1)));
        }
    }
    for(int i=1;i<=N;i++)
        for(int j=1;j<=N;j++)
            sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+mp[i][j];
    for(int x=N;x>=1;x--){
        if(N%x) continue;
        if(check(x)){
            printf("%d\n",x);
            return 0;
        }
    }
    return 0;
}

$T5:$

给定一个长度为$n$的$01$串$s$,你可以进行任意次操作:

每次操作选取一段连续且相等的串$str$,记其长度为$k(1\leq k \leq n)$。

将这段串删除并将它左边的串接到右边,同时获得$A_k$的价值。

求将整个串删除为空串所能获得的最大价值。

$n\leq 100$。

$Solution:$

这题当时触及到我的知识盲区了……(菜是原罪)考完才学了一下。

“区间消消乐”问题可以算作一种单独的$dp$模型,状态一般是

设$dp(i,j,k)$表示处理子串$[i,j]$,后面带上连续$k$个与$s_j$相同的字符所能获得的最大价值。

那么每种状态都有如下两种转移过来的方式:

  • 消后面那段颜色相同的。$dp(i,j,k)=dp(i,j-1,0)+A_k+1$
  • 枚举中间的某个断点$mid$,保证$s_{mid}=s_{j}$,此时可以把$[mid+1,j-1]$一段消去,后面接出更长的一段。$dp(i,j,k)=dp(i,mid,k+1)+dp(mid+1,j-1,0)$

时间复杂度$O(n^4)$。

$Code:$

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>

using namespace std;
#define MAXN 105
#define MAXM 500005
#define INF 0x7fffffff
#define ll long long

inline ll read(){
    ll x=0,f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar())
        if(c=='-')
            f=-1;
    for(;isdigit(c);c=getchar())
        x=x*10+c-'0';
    return x*f;
}

ll dp[MAXN][MAXN][MAXN];
ll N,A[MAXN];
char str[MAXN];

int main(){
    N=read();
    scanf("%s",str+1);
    for(ll i=1;i<=N;i++)
        A[i]=read();
    for(ll i=1;i<=N;i++)
        for(ll k=0;k<=N;k++)
            dp[i][i][k]=A[k+1];
    for(ll l=2;l<=N;l++)
        for(ll i=1;i<=N-l+1;i++){
            ll j=i+l-1;
            for(ll k=0;k<=N;k++){
                dp[i][j][k]=dp[i][j-1][0]+A[k+1];
                for(ll l=i;l<j;l++){
                    if(str[l]==str[j]) 
                    dp[i][j][k]=max(dp[i][j][k],dp[i][l][k+1]+dp[l+1][j-1][0]);
                }
            }
        }
    printf("%I64d\n",dp[1][N][0]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/YSFAC/p/10328092.html