AtCoder Beginner Contest 403(题解ABCDEF)

A - Odd Position Sum 

#1.奇数数位和

#include<iostream>
#include<vector>
#include<stdio.h>
#include<map>
#include<string>
#include<algorithm>
#include<queue>
#include<cstring>
#include<stack>
#include<array>
#include<cmath>
#include<set>
#include<unordered_set>
#include<unordered_map>
#include<iomanip>
using namespace std;
using ll = long long;
using llu = unsigned long long;
const ll inf = 0x3f3f3f3f3f3f3f3fll;
const ll MIN = -9187201950435737472ll;
ll mod = 1e9 + 7;
ll base = 131;
const int N = 1e4 + 10;
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int n;cin>>n;
    int sum=0,x;
    for(int i=1;i<=n;i++)
    {
        cin>>x;
        if(i&1)sum+=x;
    }
    cout<<sum<<endl;
	return 0;
}

B - Four Hidden  

 #1.暴力判断即可,遇到#可任意匹配

#include<iostream>
#include<vector>
#include<stdio.h>
#include<map>
#include<string>
#include<algorithm>
#include<queue>
#include<cstring>
#include<stack>
#include<array>
#include<cmath>
#include<set>
#include<unordered_set>
#include<unordered_map>
#include<iomanip>
using namespace std;
using ll = long long;
using llu = unsigned long long;
const ll inf = 0x3f3f3f3f3f3f3f3fll;
const ll MIN = -9187201950435737472ll;
ll mod = 1e9 + 7;
ll base = 131;
const int N = 1e4 + 10;
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	string s1,s2;cin>>s1>>s2;
    int n=s1.length(),m=s2.length();
    s1="#"+s1;
    s2="#"+s2;
    for(int i=1;i+m-1<=n;i++)
    {
        if(s1[i]==s2[1]||s1[i]=='?')
        {
            int j=i;
            int cnt=0;
            for(int j=i;j<=i+m-1;j++)
            {
                 if(s1[j]=='?'||s1[j]==s2[j-i+1])cnt++;
            }
            if(cnt==m)
            {
                cout<<"Yes"<<endl;
                return 0;
            }
        }
    }
    cout<<"No"<<endl;
	return 0;
}

 C - 403 Forbidden

#1.set的简单应用

#include<iostream>
#include<vector>
#include<stdio.h>
#include<map>
#include<string>
#include<algorithm>
#include<queue>
#include<cstring>
#include<stack>
#include<array>
#include<cmath>
#include<set>
#include<unordered_set>
#include<unordered_map>
#include<iomanip>
using namespace std;
using ll = long long;
using llu = unsigned long long;
const ll inf = 0x3f3f3f3f3f3f3f3fll;
const ll MIN = -9187201950435737472ll;
ll mod = 1e9 + 7;
ll base = 131;
const int N = 2e6+ 10;
set<pair<int,int>>st;
bool vis[N];
int main()
{
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int n,m,q;cin>>n>>m>>q;
    int ty,x,y;
    while(q--)
    {
        cin>>ty;
        if(ty==1)
        {
            cin>>x>>y;
            st.insert({x,y});
        }
        else if(ty==2)
        {
            cin>>x;
            vis[x]=true;
        }
        else
        {
            cin>>x>>y;
            if(vis[x])cout<<"Yes"<<endl;
            else
            {
                if(st.count({x,y}))cout<<"Yes"<<endl;
                else cout<<"No"<<endl;
            }
        }
    }
	return 0;
}

D - Forbidden Difference 

给一个序列,我们需要删除一些元素,让剩下元素满足任意两个差的绝对值不等于d,问删的最小值

#1.给定ai和d的值域都很小,可以开一个1e6的桶,来记录ai中每个值出现的次数

#2.注意到当差的绝对值为d时,在1e6的范围中是以d为步幅递增的,也就是同余的,考虑将数对d取模 ,单独存在一个vector中,存在vector的中的是出现次数

#3.于是问题变成了一个经典dp问题--相邻不取取最大,最后拿总数减剩下的就是答案(特判d==0)

#include<iostream>
#include<vector>
#include<stdio.h>
#include<map>
#include<string>
#include<algorithm>
#include<queue>
#include<cstring>
#include<stack>
#include<array>
#include<cmath>
#include<set>
#include<unordered_set>
#include<unordered_map>
#include<iomanip>
using namespace std;
using ll = long long;
using llu = unsigned long long;
const ll inf = 0x3f3f3f3f3f3f3f3fll;
const ll MIN = -9187201950435737472ll;
ll mod = 1e9 + 7;
ll base = 131;
const int N = 1e6+10;
const int M=1e6;
int cnt[N];
int a[N];
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int n,d;cin>>n>>d;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        cnt[a[i]]++;
    }
    if(d==0)
    {
        int sz=0;
        for(int i=0;i<=M;i++)
        {
            sz+=cnt[i]>0;
        }
        cout<<n-sz<<endl;
        return 0;
    }
    int sum=0;
    for(int i=0;i<d;i++)
    {
        vector<int>b(1,0);
        for(int j=i;j<=M;j+=d)
        {
            b.push_back(cnt[j]);
        }
        int sz=b.size()-1;
        vector<int>dp(sz+1,-1);
        dp[1]=b[1];
        if(sz>=2)dp[2]=max(dp[1],b[2]);
        for(int j=3;j<=sz;j++)
        {
            dp[j]=max(dp[j-1],dp[j-2]+b[j]);
        }
        sum+=dp[sz];
    }
    cout<<n-sum<<endl;
	return 0;
}

 E - Forbidden Prefix

给两个字符串集合x和y,q次操作,操作1是向x中添加字符串,操作2是对y中添加字符串,每次添加后输出y中不以x中字符串为前缀的字符串

#1.求解字符串前缀问题考虑字典树,要维护e数组,即有多少字符串经过该节点,每次要输出的就是e[0]

#2.对操作1的删除,有两种情况,一种是添加的这个字符串它的前缀已经在x中出现,那就不用考虑,可以用vis标记x中字符串结尾,经过vis不为0的节点,说明前缀出现过。另一种是从未出现过,那就要将经过过该节点的节点都要减去这个节点的e值,代表这个前缀已经删除

#3.接下来是向y中添加字符串,判断路径是否经过x的前缀即可,用vis判断

#include<iostream>
#include<vector>
#include<stdio.h>
#include<map>
#include<string>
#include<algorithm>
#include<queue>
#include<cstring>
#include<stack>
#include<array>
#include<cmath>
#include<set>
#include<unordered_set>
#include<unordered_map>
#include<iomanip>
using namespace std;
using ll = long long;
using llu = unsigned long long;
const ll inf = 0x3f3f3f3f3f3f3f3fll;
const ll MIN = -9187201950435737472ll;
ll mod = 1e9 + 7;
ll base = 131;
const int N = 1e5 + 10;
int nxt[30*N][26];
int vis[30*N],cnt=0,sz=0,l,e[30*N];
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int q,ty;cin>>q;
    string s;
    while(q--)
    {
        cin>>ty;
        if(ty==1)
        {
            cin>>s;
            l=s.length();
            int now=0;
            bool tag=true;
            for(int i=0;i<l;i++)
            {
                int x=s[i]-'a';
                if(!nxt[now][x])nxt[now][x]=++cnt;
                now=nxt[now][x];
                if(vis[now])tag=false;
            }
            vis[now]=1;
            if(tag)
            {
                int y=0;
                e[y]-=e[now];
                for(int i=0;i<l;i++)
                {
                    int x=s[i]-'a';
                    y=nxt[y][x];
                    e[y]-=e[now];
                }
            }
        }
        else
        {
            cin>>s;
            l=s.length();
            int now=0;
            bool tag=true;
            for(int i=0;i<l;i++)
            {
                int x=s[i]-'a';
                if(!nxt[now][x])nxt[now][x]=++cnt;
                now=nxt[now][x];
                if(vis[now])tag=false;
            }
            if(tag)
            {
                now=0;
                e[now]++;
                for(int i=0;i<l;i++)
                {
                    int x=s[i]-'a';
                    now=nxt[now][x];
                    e[now]++;
                }
            }
        }
        cout<<e[0]<<endl;
    }
	return 0;
}

F - Shortest One Formula 

用一些1和+,*来构成一个表达式,使其结果为n,求最短表达式

#1.n只有2000,考虑暴力递推,由于一个加法表达式和一个乘法表达式相乘时加法表达式需要加括号,那就将加法与乘法分开考虑,给f[i]表示最后一次操作是加法结果是i的字符串,g[i]表示最后一次操作时乘法结果时i的字符串

#2.从1递推到n,特判1,11,111,1111,其他的递推到i是,分解i为x+y后x*y,一一枚举,更新f[i]与g[i]

#include<iostream>
#include<vector>
#include<stdio.h>
#include<map>
#include<string>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<stack>
#include<array>
#include<cmath>
#include<set>
#include<unordered_set>
#include<unordered_map>
#include<iomanip>
using namespace std;
using ll = long long;
using llu = unsigned long long;
const ll inf = 0x3f3f3f3f3f3f3f3fll;
const ll MIN = -9187201950435737472ll;
ll mod = 1e9 + 7;
ll base = 131;
const int N =2e3+10;
string f[N],g[N];
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int n;cin>>n;
    for(int i=1;i<=n;i++)
    {
        if(i==1)
        {
            f[i]="1";
            g[i]="1";
        }
        else if(i==11)
        {
            f[i]="11";
            g[i]="11";
        }
        else if(i==111)
        {
            f[i]="111";
            g[i]="111";
        }
        else if(i==1111)
        {
            f[i]="1111";
            g[i]="1111";
        }
        else
        {
            f[i]=f[1]+"+"+f[i-1];
            for(int x=1;x+x<=i;x++)
            {
                int y=i-x;
                if(f[x].size()+f[y].size()+1<f[i].size())
                {
                    f[i]=f[x]+"+"+f[y];
                }
                if(f[x].size()+g[y].size()+1<f[i].size())
                {
                    f[i]=f[x]+"+"+g[y];
                }
                if(g[x].size()+f[y].size()+1<f[i].size())
                {
                    f[i]=g[x]+"+"+f[y];
                }
                if(g[x].size()+g[y].size()+1<f[i].size())
                {
                    f[i]=g[x]+"+"+g[y];
                }
            }
            g[i]="("+f[i]+")"+"*"+g[1];
            for(int x=1;x<=i/x;x++)
            {
                if(i%x)continue;
                int y=i/x;
                if(f[x].size()+f[y].size()+5<g[i].size())
                {
                    g[i]="("+f[x]+")"+"*"+"("+f[y]+")";
                }
                if(f[x].size()+g[y].size()+3<g[i].size())
                {
                    g[i]="("+f[x]+")"+"*"+g[y];
                }
                if(g[x].size()+f[y].size()+3<g[i].size())
                {
                    g[i]=g[x]+"*"+"("+f[y]+")";
                }
                if(g[x].size()+g[y].size()+1<g[i].size())
                {
                    g[i]=g[x]+"*"+g[y];
                }
            }
        }
    }
    if(f[n].size()<g[n].size())
    {
        cout<<f[n]<<endl;
    }
    else cout<<g[n]<<endl;
	return 0;
}

 

 

 

AtCoder Beginner Contest 134 是一场 AtCoder 的入门级比赛,以下是每道题的简要题解: A - Dodecagon 题目描述:已知一个正十二边形的边长,求它的面积。 解题思路:正十二边形的内角为 $150^\circ$,因此可以将正十二边形拆分为 12 个等腰三角形,通过三角形面积公式计算面积即可。 B - Golden Apple 题目描述:有 $N$ 个苹果和 $D$ 个盘子,每个盘子最多可以装下 $2D+1$ 个苹果,求最少需要多少个盘子才能装下所有的苹果。 解题思路:每个盘子最多可以装下 $2D+1$ 个苹果,因此可以将苹果平均分配到每个盘子中,可以得到最少需要 $\lceil \frac{N}{2D+1} \rceil$ 个盘子。 C - Exception Handling 题目描述:给定一个长度为 $N$ 的整数序列 $a$,求除了第 $i$ 个数以外的最大值。 解题思路:可以使用两个变量 $m_1$ 和 $m_2$ 分别记录最大值和次大值。遍历整个序列,当当前数不是第 $i$ 个数时,更新最大值和次大值。因此,最后的结果应该是 $m_1$ 或 $m_2$ 中较小的一个。 D - Preparing Boxes 题目描述:有 $N$ 个盒子和 $M$ 个物品,第 $i$ 个盒子可以放入 $a_i$ 个物品,每个物品只能放在一个盒子中。现在需要将所有的物品放入盒子中,每次操作可以将一个盒子内的物品全部取出并分配到其他盒子中,求最少需要多少次操作才能完成任务。 解题思路:首先可以计算出所有盒子中物品的总数 $S$,然后判断是否存在一个盒子的物品数量大于 $\lceil \frac{S}{2} \rceil$,如果存在,则无法完成任务。否则,可以用贪心的思想,每次从物品数量最多的盒子中取出一个物品,放入物品数量最少的盒子中。因为每次操作都会使得物品数量最多的盒子的物品数量减少,而物品数量最少的盒子的物品数量不变或增加,因此这种贪心策略可以保证最少需要的操作次数最小。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值