Codeforces 1062 - A/B/C/D/E - (Undone)

連接:http://codeforces.com/contest/1062c++


A - Prank - [二分]

題意:數組

給出長度爲 $n(1 \le n \le 100)$ 的數組 $a[1 \sim n]$,且知足 $1 \le a[1] < a[2] < \cdots < a[n] \le 1000$。如今JATC要擦掉其中一段連續的數字,可是要求可以經過剩餘的其餘數字,推斷出擦掉的數字是什麼。求JATC能擦掉的最長長度。spa

題解:code

其實 $O(n)$ 就能夠求出能擦掉的最長長度,可是由於 $n$ 比較小,懶得考慮太多,直接二分吧……blog

二分能擦掉的長度,對於固定的長度,$O(n)$ 枚舉始末點判斷可否擦除便可。ci

AC代碼:get

#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
int n,a[maxn];
bool judge(int k)
{
    for(int i=1,j=i+k-1;j<=n;i++,j++) {
        if(a[j+1]-a[i-1]==k+1) return 1;
    }
    return 0;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    a[0]=0, a[n+1]=1001;
    int l=0, r=n;
    while(l<r)
    {
        int mid=(l+r+1)/2;
        if(judge(mid)) l=mid;
        else r=mid-1;
    }
    cout<<l<<endl;
}

 


B - Math - [數學題]

題意:數學

給出一個正整數 $n(1 \le n \le 1e6)$,你如今能夠對 $n$ 進行任意屢次乘以正整數 $x$ 或者開方(當結果爲整數時才容許開方)操做。it

求結果最小爲多少,達到這個結果最少進行多少次操做。class

題解:

分解質因數 $n = {p_1}^{a_1}{p_2}^{a_2} \cdots {p_k}^{a_k}$,顯然最後結果只能是 $p_1 p_2 \cdots p_k$,那麼如何才能獲得 $p_1 p_2 \cdots p_k$?

找到 $\max(a_i)$,求得比小於它的最小 $2^x$,這樣一來先作一次乘法把 $n$ 乘到 ${p_1}^{2^x}{p_2}^{2^x} \cdots {p_k}^{2^x}$,而後作 $2^x$ 次開方操做便可獲得 $p_1 p_2 \cdots p_k$。所以最少 $x+1$ 次操做。

(固然,還有一些數字自己就是最小結果,這些另做判斷便可。)

AC代碼:

#include<bits/stdc++.h>
using namespace std;
int n;
pair<int,int> solve(int n)
{
    if(n<=1) return make_pair(n,0);
    int res=1,mx=0, mn=20;
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            res*=i;
            int cnt=0;
            while(n%i==0) n/=i, cnt++;
            mx=max(cnt,mx);
            mn=min(cnt,mn);
        }
    }
    if(n>1) res*=n, mx=max(1,mx), mn=min(1,mn);
    int t=ceil(log2(mx))+1e-8;
    if(mn==mx && (1<<t)==mx) return make_pair(res,t);
    else return make_pair(res,t+1);
}
int main()
{
    while(cin>>n)
    {
        pair<int,int> ans=solve(n);
        cout<<ans.first<<' '<<ans.second<<endl;
    }
}

 


C - Banh-mi - [簡單思惟題][貪心+前綴和+快速冪]

題意:

有一個食物,將其分紅 $n(1 \le n \le 1e5)$ 份,編號爲 $1 \sim n$,第 $i$ 份食物的初始美味度爲 $x_i(x_i \in {0,1})$,

如今有 $q(1 \le q \le 1e5)$ 次查詢,每一個查詢 $[l,r]$ 表明如今只考慮該區間內的食物,每次我吃其中的某一份食物 $i$,個人喜悅程度就會加上 $x_i$,同時區間內全部其餘剩餘的食物的 $x_j$ 都會加上 $x_i$。

如今要求對每一個查詢,輸出我最大能得到的喜悅程度。

題解:

首先確定是貪心地吃食物,每次都吃 $x_i$ 最大的食物。

假設初始區間內有 $a$ 個 $1$,$b$ 個 $0$,那麼先吃完全部初始美味度爲 $1$ 的食物,獲得喜悅程度爲

$1 + 2 + 4 + \cdots + 2^{a-1} = 2^0 + 2^1 + 2^2 + \cdots + 2^{a-1} = 2^a - 1$

接下來,剩下的初始美味度爲 $0$ 的食物,如今美味度都變成了 $2^a - 1$,吃完這些食物獲得喜悅程度爲

$(2^a - 1) \cdot 2^0 + (2^a - 1) \cdot 2^1 + \cdots + (2^a - 1) \cdot 2^{b-1} = (2^a - 1)(2^0 + 2^1 + \cdots + 2^{b-1}) = (2^a - 1)(2^b - 1)$

所以我只須要經過前綴和,就能 $O(1)$ 統計出任意區間內 $0$ 和 $1$ 的數目,而後只須要快速冪求出 $2^a - 1 + (2^a - 1)(2^b - 1) = (2^a - 1)2^b$ 便可。

AC代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=1e5+10;
int n,q;
char s[maxn];
int c[2][maxn];
ll fpow(ll a,ll n)
{
    ll res=1,base=a%mod;
    while(n)
    {
        if(n&1) res*=base, res%=mod;
        base*=base, base%=mod;
        n>>=1;
    }
    return res%mod;
}
int main()
{
    scanf("%d%d",&n,&q);
    scanf("%s",s+1);
    c[0][0]=c[1][0]=0;
    for(int i=1,x;i<=n;i++)
    {
        x=s[i]-'0';
        c[x][i]=c[x][i-1]+1;
        c[x^1][i]=c[x^1][i-1];
    }
    for(int i=1,l,r;i<=q;i++)
    {
        scanf("%d%d",&l,&r);
        ll a=c[1][r]-c[1][l-1], b=c[0][r]-c[0][l-1];
        printf("%lld\n",(fpow(2,a+b)-fpow(2,b)+mod)%mod);
    }
}

 


D - Fun with Integers - []

 


E - Company - []

相關文章
相關標籤/搜索