codeforces 1295 题解

codeforces 1295 题解

A. Display The Number

给你可显示的总数,让你凑个最大的数,很明显,抽象的思想就是“好钢要用在刀刃上”,如果可显示的数字越大,所消耗的越小,他自然更好。

我们观察一下各个数字的消耗情况:

0 1 2 3 4 5 6 7 8 9
6 2 5 5 4 5 6 3 7 6

数字 \(9\) 比数字 \(8,6\) 要大,消耗还不比他们多,所以答案中肯定不出现 \(8,7,6\) (单调队列思想)。

这样一看,答案中只有可能出现数字 \(1,7,9\) 。我们再思考一下,一个数字大,他怎么算大?每一位最大的数字大他就一定大?显然不是,判断两个数哪个大,首先要比较位数(大数思想),位数大的自然也就更大。

我们枚举一下,如果我们的可显示总数只有 \([2,3]\) 个,自然都只能凑成一位数了,但如果有 \(4\) 个呢?我们可以用两个 \(1\) 凑成两位数 \(11\) ,如果我们有 \(6\) 个就能凑成 \(111\),有点感觉以后我们发现好像答案中也不会出现 \(9\) 了,因为“两拳难敌四手”,凑成一个 \(9\) 的代价过高,不如用它多凑几位 \(1\)

事实上,如果给你偶数个可显示总数,你就用他们都来凑 \(1\) 就行,最后刚刚好。如果给你奇数个,那你可以先凑一个 \(7\),把它放在最高位,这样也就不会有剩下的了。可以证明答案中最多出现一个 \(7\),因为出现两个或者以上,那不如用他们多凑几个 \(1\)。详细证明过程略,意思领会就好。

时间复杂度 \(O(n)\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define _for(i,a,b) for(int i = (a);i < b;i ++)
#define _rep(i,a,b) for(int i = (a);i > b;i --)
#define INF 0x3f3f3f3f3f3f3f3f
#define ZHUO 11100000007
#define SHENZHUO 1000000007
#define pb push_back
#define debug() printf("Miku Check OK!\n")
#define maxn 20003
#define X first
#define Y second
 
 
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        string rnt;
        if(n&0x1)
            n -= 3,rnt += '7';
        while(n>0)
            n -= 2,rnt += '1';
        printf("%s\n",rnt.c_str());
    }
    return 0;
}

B. Infinite Prefixes

根据它给的那个 \(balance\) 公式,我们可以转换一下:字符串 \(t\) 每出现一个 \(0\) ,其实就是 \(balance\)\(+1\),出现一个 \(1\) 就是 \(balance\)\(-1\)。然后我们就能根据字符串 \(t\) 构造一个整数数组 \(a\)。我们就拿样例 \(1\) 说事儿:

t 0 1 0 0 1 0
a 1 0 1 2 1 2

那这个数组 \(a\) 有啥子用?我们思考这个字符串 \(t\) 是怎么来的,没错,就是通过字符串 \(s\) 复读来的,那么我们把这个 \(a\) 数组往下写一写,找找规律:

\(1,0,1,2,1,2,3,2,3,4,3,4......\)

复读一遍,我们发现第 \(i(i≥1)\) 位这个数怎么来?我给你一个公式你看看对不对:

\(a_{k,i}=a_{1,i}+a_{1,n}×k\)

其中 \(a_{i,j}\) 代表第 \(i\) 组第 \(j\) 个。

那这样我们就能在预处理出 \(a\) 以后快速计算出第 \(?\) 个数了。我们继续观察这个数组, \(a\) 数组里不同组但是组内相对位置相同则整体单调,所以只有末尾那个数为 \(0\) 的时候才有可能输出 \(-1\)。只有末尾那个数为 \(0\) 还不够,还要中间出现 \(x\) 这个数才输出 \(-1\)

处理完特殊情况以后我们再继续思考,既然后面都是复读的,而且单调增或者减,我们的 \(x\) 是不变的,那么 \(x\) 对于组内相对位置相同时,在不同组只有可能出现 \(1\) 次,因此我们就看第一组然后算后面的那些个组,该位置应该是什么数,如果能等于 \(x\) ,那说明 \(x\) 可以在该相对位置出现一次,否则就不能。

根据上面的公式随便搞一搞算一算看看能不能整除,就能判断 \(x\) 在该组内相对位置能否出现,能答案就 \(+1\) ,注意特殊考虑 \(0\) 的情况。

时间复杂度 \(O(n)\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define _for(i,a,b) for(int i = (a);i < b;i ++)
#define _rep(i,a,b) for(int i = (a);i > b;i --)
#define INF 0x3f3f3f3f3f3f3f3f
#define ZHUO 11100000007
#define SHENZHUO 1000000007
#define pb push_back
#define debug() printf("Miku Check OK!\n")
#define maxn 100003
#define X first
#define Y second

bool judge(int a,int b)
{
    if(!a || (!a && !b))
        return true;
    if(!b)
        return false;
    return ((a/abs(a))*(b/abs(b)))>0 && !(a%b);
}

int T;
int main()
{
    ios::sync_with_stdio(false);
    cin >> T;
    while(T--)
    {
        int n, x;string s;
        cin >> n >> x >> s;
        int a[maxn];
        
        a[0] = 0;
        _for(i,0,n)
            a[i+1] = a[i] + ((!(s[i]-'0')) ? 1 : -1);
        
        int rnt = 0;
        if(!a[n])
        {
            _for(i,1,n+1)
                if(a[i]==x)
                    rnt = -1;
            if(rnt==-1)
            {
                printf("-1\n");
                continue;
            }
        }
        
        if(!x)
            rnt ++;
        _for(i,1,n+1)
        {
            int tmpx = x;
            tmpx -= a[i];
            if(judge(tmpx,a[n]))
                rnt ++;
        }
        printf("%d\n",rnt);
    }
    return 0;
}

C. Obtain The String

既然是从字符串 \(s\) 中取子序列凑 字符串 \(t\) ,那就贪心的去凑就可以了:每一次从 \(s\) 中取出的字符串自然越长越好。

关键是我们不能对于每个 \(t\) 中的字符都往后面无脑扫一遍 \(s\) ,那是 \(O(n^2)\) 的时间复杂度,那我们就想点好方法快点扫不就完事儿了吗!怎么快呢,我们预处理 \(dp[i][j]\) 表示在字符串 \(s\) 下标为 \(i\) 的地方,后面最靠近该位置的字母 \(j+'a'\) 的下标是多少 ,这样到时候我们就能跳着扫 \(s\) ,这样就快的多了。

输出 \(-1\) 的情况既很好判断也很好理解:字符串 \(t\) 中出现了 字符串 \(s\) 中没有的字母自然就凑不出来咯!

时间复杂度 \(O(max(|s|,|t|))\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define _for(i,a,b) for(int i = (a);i < b;i ++)
#define _rep(i,a,b) for(int i = (a);i > b;i --)
#define INF 0x3f3f3f3f3f3f3f3f
#define ZHUO 11100000007
#define SHENZHUO 1000000007
#define MIKUNUM 39
#define pb push_back
#define debug() printf("Miku Check OK!\n")
#define maxn 100003
#define X first
#define Y second

//MIKUNUM是我喜欢的数字,没啥意义,你也可以改成,40,50,或者30,都行
int T;
string s, t;
int latest[MIKUNUM];
int dp[maxn][MIKUNUM];

bool judge()
{
    _for(i,0,t.size())
        if(latest[t[i]-'a']==-1)
            return false;
    return true;
}
int main()
{
    ios::sync_with_stdio(false);
    cin >> T;
    while(T--)
    {
        cin >> s >> t;
        //这里初始化的可能有点多了,放在程序最后然后根据当前输入量初始化能省点时间
        memset(latest,-1,sizeof(latest));
        memset(dp,-1,sizeof(dp));
        
        _rep(i,s.size()-1,-1)
        {
            _for(j,0,26)
                dp[i][j] = latest[j];
            latest[s[i]-'a'] = i;
        }
        
        if(!judge())
        {
            printf("-1\n");
            continue;
        }
        
        int rnt = 0;
        int s_in = -1;
        _for(i,0,t.size())
        {
            if(s_in==-1)
            {
                rnt ++;
                s_in = latest[t[i]-'a'];
                continue;
            }
            s_in = dp[s_in][t[i]-'a'];
            (s_in == -1) ? i-- : MIKUNUM;
        }
        printf("%d\n",rnt);
    }
    return 0;
}

D. Same GCDs

数论题,卓爷的锅,我就不背了,$ %ZHUO$

E. Permutation Separation

我妈让我不要久坐,等会儿回来再看

F. Good Contest

数论概率论,还是卓爷的锅,卓爷 \(tql\)

猜你喜欢

转载自www.cnblogs.com/Asurudo/p/12242236.html