AtCoder-arc060 (题解)

A - 高橋君とカード / Tak and Cards (DP)

题目链接

题目大意:

有 \(n\) 个数字,要求取出一些数字,使得它们的平均数恰好为 \(x\) ,问有几种取法。

大致思路:

只要将每一个数字减掉 \(x\) ,那么问题就变成在 \(n\) 个数字中选取一些数字使得和为 \(0\) 的方案数,是一个经典的 \(dp\) 问题,不过要注意细节问题

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=5010;
const int Y=2500;
ll dp[N][N];
int n,x;
int a[N];
int main()
{
    //freopen("H:\\c++1\\in.txt","r",stdin);
    //freopen("H:\\c++1\\out.txt","w",stdout);
    scanf("%d%d",&n,&x);
    dp[0][Y]=1;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),a[i]-=x;
    for(int i=1;i<=n;i++){
        for(int j=-Y;j<=Y;j++){
            dp[i][j+Y+a[i]]+=dp[i-1][j+Y];
            dp[i][j+Y]+=dp[i-1][j+Y];
        }
    }
    printf("%lld\n",dp[n][Y]-1); //记得减一
    return 0;
}

B - 桁和 / Digit Sum (思维)

题目链接

题目大意:

定义 \(f(n,b)\) 为 \(n\) 在 \(b\) 进制下各位数之和,现在给定 \(,n,s\) ,为求得最小的 \(b\) 使得 \(f(n,b)=s\)

\((n,s<=1e11)\)

大致思路:

这题很巧妙,首先如果答案 \(b\) 小于 \(1e6\) ,那么直接暴力枚举即可,若 \(b>1e6\) ,那么由于 \(n<=1e11\) ,那么 \(n\) 必然可以写成 \(n=kb+r\) ,且 \(s=k+r\) ,的形式, \(n-s=k(b-1)\) ,只要枚举 \(n-s\) 的因数即可解决,思维好题。

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,s;
bool check(ll x){
    if(n/x>=x)return 0;
    if(x<2)return 0;
    ll k=n/x;ll r=n%x;
    if(s==k+r)return 1;
    return 0;
}
ll js(ll x,ll b){
    ll ans=0;
    while(x){
        ans+=x%b;
        x/=b;
    }
    return ans;
}
int main()
{
    //freopen("H:\\c++1\\in.txt","r",stdin);
    //freopen("H:\\c++1\\out.txt","w",stdout);
    cin>>n>>s;
    ll b=1e18;
    if(n==s)b=n+1;
    if(n>s){
        ll temp=n-s;
        for(ll t=1;t<=sqrt(temp);t++){
            if(temp%t==0){
                ll x=t+1,y=temp/t+1;
                if(check(x))b=min(b,x);
                if(check(y))b=min(b,y);
            }
        }
    }
    for(ll t=2;t<=1000000;t++){
        ll cnt=js(n,t);
        if(cnt==s){
            b=min(b,t);
            break;
        }
    }
    if(b==1e18)printf("-1\n");
    else printf("%lld\n",b);
    return 0;
}

E - 高橋君とホテル / Tak and Hotels (倍增)

题目链接

题目大意:

水平轴上有 \(n\) 个点,每次跳不能超过 \(L\) ,每次必须跳在点上, \(Q\) 次询问,每次询问 \(,x,y\) ,表示从 \(x\) 到 \(y\) 最少需要跳几下。

大致思路:

感觉这题比较常见,是倍增的经典套路,用二分处理出 \(dp[i][0]\) ,跑一下预处理,然后就每次询问log查询就行了。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int dp[N][23];
int n,L;
int a[N];
int q,x,y;
int ef(int id,int v){
    int l=id,r=n,ans=id;
    while(l<=r){
        int mid=(l+r)/2;
        if(a[mid]<=v)ans=mid,l=mid+1;
        else r=mid-1;
    }
    return ans;
}
void cl(){ //
    for(int i=1;i<=n;i++)dp[i][0]=ef(i,a[i]+L);
    for(int j=1;j<23;j++){
        for(int i=1;i<=n;i++){
            dp[i][j]=dp[dp[i][j-1]][j-1];
        }
    }
}
int js(int x,int y){
    int ans=0,pos=x;
    for(int i=22;i>=0;i--){
        if(dp[pos][i]<y){
            pos=dp[pos][i];
            ans+=(1<<i);
        }
    }
    ans++;
    return ans;
}
int main()
{
    //freopen("H:\\c++1\\in.txt","r",stdin);
    //freopen("H:\\c++1\\out.txt","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    scanf("%d",&L);
    scanf("%d",&q);
    cl();
    while(q--){
        scanf("%d%d",&x,&y);
        if(x>y)swap(x,y);
        printf("%d\n",js(x,y));
    }
    return 0;
}

D - 最良表現 / Best Representation (KMP)

题目链接

题意大意:

定义一个字符串合法:当该字符串没有循环节存在,给出 \(string s\) ,令 \(F=(f_1,f_2..f_m)\) 满足 \(f_i\) 为 \(s\) 的某一部分. \(f_1,f_2,..f_m\) 连起来为 \(s\) .并且任意 \(f_i\) 为合法
\(|s|<=5e5\),求出 \(F\) 表示中最小的 \(m\) .并求出最小 \(m\) 的方案数?

大致思路:

这题感觉不难,只是由于是最后一题心理上有些畏惧,可惜了,首先先求出字符串的循环节,如果不存在循环节那么答案就是 \(1\ 1\) ,特判每一个字母都相同的情况答案为 \(len\ 1\) ,比较显然,那么我们可以确定剩下的字符串必然可以分成两个好串,那么我们只要枚举断点用 \(kmp\) 判断前面的字符串和后面的字符串是否为好串即可,代码实现也比较简单。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
char s[N];
char s1[N];
int nxt[N],nxt1[N];//next数组
void kmp(char *t,int *nxt){//t为去匹配,s为被匹配
    int i,j;
    int len1=strlen(t+1);
    nxt[0]=nxt[1]=0;
    for(i=2,j=0;i<=len1;i++){
        while(j&&t[j+1]!=t[i])j=nxt[j];
        if(t[j+1]==t[i])++j;
        nxt[i]=j;
    }
}
bool check(int x,int len){
    int f1,f2;
    int l1=x-nxt[x],l2=len-x-(nxt1[len-x]);
    //if(x==2)cout<<l1<<" "<<l2<<endl;
    if(x==1||l1==x||x%l1!=0)f1=1;
    else f1=0;
    if(len-x==1||l2==len-x||(len-x)%l2!=0)f2=1;
    else f2=0;
    return (f1&&f2);
}
int main()
{
    //freopen("H:\\c++1\\in.txt","r",stdin);
    //freopen("H:\\c++1\\out.txt","w",stdout);
    scanf("%s",s+1);
    int len=strlen(s+1);
    for(int i=1;i<=len;i++){
        s1[i]=s[len-i+1];
    }
    kmp(s,nxt);kmp(s1,nxt1);
    int temp=len-nxt[len];
    if(temp==1){
        printf("%d\n%d\n",len,1);return 0;
    }
    if(temp!=len&&len%temp==0){
        int ans=0;
        for(int i=1;i<len;i++){
            if(check(i,len))ans++;
        }
        printf("2\n%d\n",ans);
    }
    else{
        printf("1\n1\n");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/C-W-K/p/11988833.html

时间: 2024-10-11 08:55:36

AtCoder-arc060 (题解)的相关文章

[AtCoder][ARC082]Sandglass 题解

Sandglass 时间限制: 1 Sec 内存限制: 128 MB 原题链接 https://arc082.contest.atcoder.jp/tasks/arc082_d 题目描述 We have a sandglass consisting of two bulbs, bulb A and bulb B. These bulbs contain some amount of sand. When we put the sandglass, either bulb A or B lies

AtCoder Beginner Contest 115 题解

题目链接:https://abc115.contest.atcoder.jp/ A Christmas Eve Eve Eve 题目: Time limit : 2sec / Memory limit : 1024MB Score : 100 points Problem Statement In some other world, today is December D-th. Write a program that prints Christmas if D=25, Christmas E

AtCoder Beginner Contest 154 题解

人生第一场 AtCoder,纪念一下 话说年后的 AtCoder 比赛怎么这么少啊(大雾 AtCoder Beginner Contest 154 题解 A - Remaining Balls We have A balls with the string S written on each of them and B balls with the string T written on each of them. From these balls, Takahashi chooses one

【ATcoder】AtCoder Beginner Contest 161 题解

题目链接:AtCoder Beginner Contest 161 原版题解链接:传送门 A - ABC Swap 这题太水,直接模拟即可. 1 #include <iostream> 2 using namespace std; 3 int main() { 4 int a, b, c; 5 cin >> a >> b >> c; 6 swap(a, b); 7 swap(a, c); 8 cout << a << " &

题解 [Atcoder ABC 161] A,B,C

题解 [Atcoder ABC 161] A,B,C A: 水题,按题意模拟即可. code: #include<bits/stdc++.h> #define ft(i,l,r) for(register int i=l;i<=r;i++) #define fd(i,r,l) for(register int i=r;i>=l;i--) using namespace std; int a,b,c; int main() { cin>>a>>b>>

【AtCoder】ARC096 C-F题解

听说日本题思维都很棒,去涨涨智商qwq C - Half and Half 题解 枚举买多少个AB披萨也行 但是关于买x个AB披萨最后的总花费是个单峰函数,可以三分 这题有点像六省联考2017D1T1送分题期末考试 代码 #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #define MAXN 100005 #define PLI pair<lo

【AtCoder】AGC023 A-F题解

可以说是第一场AGC了,做了三道题之后还有30min,杠了一下D题发现杠不出来,三题滚粗了 rating起步1300+,感觉还是很菜... 只有三题水平显然以后还会疯狂--啊(CF的惨痛经历) 改题的感觉似乎还不错因为思维都非常的妙(我根本想不到) A - Zero-Sum Ranges 开场娱乐大家的小水题,区间和为0的情况存在于sum[R] == sum[L - 1],只要记录一下某一个值的sum出现了多少次就行,懒得离散化直接用map就OK啊 代码 #include <iostream>

【AtCoder】ARC100 题解

C - Linear Approximation 找出\(A_i - i\)的中位数作为\(b\)即可 题解 #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #define enter putchar('\n') #define space putchar(' ') #define fi first #define se second #define

【题解】Atcoder AGC#16 E-Poor Turkeys

%拜!颜神怒A此题,像我这样的渣渣只能看看题解度日╭(╯^╰)╮在这里把两种做法都记录一下吧~ 题解做法:可以考虑单独的一只鸡 u 能否存活.首先我们将 u 加入到集合S.然后我们按照时间倒序往回推,如果在时间 t 的时候发现有 u 和 v 同时被抉择,为了保证 u 的存活我们只能杀掉 v,也就是说在 t - 1的时刻 v 必须存活.这时我们将 v 加入到集合 S 中,再继续进行这个过程.如果在某个时刻我们发现 u 和 v 同时被抉择,可 u 和 v 都已经在集合中出现过了(要求在这个时刻一并存

AtCoder Beginner Contest 121 题解

题目链接:https://atcoder.jp/contests/abc121 A White Cells 分析:题目数据规模很小,直接暴力修改都可以.或者可以推出公式. 代码: 1 #include <iostream> 2 #include <cstdio> 3 4 using namespace std; 5 6 int main() 7 { 8 int a[25][25] = {0}; 9 int H, W, h, w; 10 scanf("%d %d"