1. 程式人生 > >水題合集

水題合集

 
HDU 5101
題意:n個班級 第i個班級有num[i]個人,第j個人的戰鬥力為v[i][j].
n<=1e3,num[i]<=100,v[i],k<=1e9.問從n個班級中選兩個人其戰鬥力和>k並且兩個人不在同一班時的方案數?

把所有人的戰鬥裡存到某個陣列b中 然後將b排序.
列舉第一個人為第i個班級第j個人,其戰鬥力為x,

則快速找到b中第一個>k-x的位置pos 則a[i][j]貢獻tot-pos+1.然後在a[i]中二分,扣掉同一班級的即可.

O(n*m log tot)     (a,b),(b,a)都被列舉 答案最後除以2

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e3+5;
ll a[N][110],num[N],b[N*N];
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        ll n,k,tot=0;
        scanf("%lld%lld",&n,&k);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&num[i]);
            for(int j=1;j<=num[i];j++)
                scanf("%lld",&a[i][j]),b[++tot]=a[i][j];
            sort(a[i]+1,a[i]+1+num[i]);
        }
        sort(b+1,b+1+tot);
        ll ans=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=num[i];j++)
            {
                ll x=k-a[i][j]+1;
                ll pos=lower_bound(b+1,b+1+tot,x)-(b+1)+1;
                ans+=(tot-pos+1ll);
                ll same=lower_bound(a[i]+1,a[i]+1+num[i],x)-(a[i]+1)+1;
                ans-=(num[i]-same+1ll);
            }
        }
        printf("%lld\n",ans/2);
    }
    return 0;
}



HDU 5056
題意:給出字串s,問s中有多少個子串滿足:子串中每個字元的出現次數不超過k,|s|,k<=1e5.
列舉[le,rg] 當rg不合法時 從[le+1,rg]繼續開始列舉,雙指標弄一弄即可 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
char s[N];
int num[30];
int main()
{
    int T,k;
    cin>>T;
    while(T--)
    {
        memset(num,0,sizeof(num));
        scanf("%s%d",s+1,&k);
        int n=strlen(s+1),rg=1;
        long long ans=0;
        for(int le=1;le<=n;le++)
        {
            while(rg<=n)
            {
                if(num[s[rg]-'a']<k)
                    num[s[rg]-'a']++,rg++;
                else
                    break;
            }
            ans+=rg-le;
            num[s[le]-'a']--;
        }
        cout<<ans<<endl;
    }
    return 0;
}
HDU 5167
題意:T次詢問,每次給出一個數x,問x是否能寫成若干個fib數的乘積.T<=1e5,x<=1e9


fib數增長恨快,不大於1e9的fib只有45個.
暴力列舉乘積中的第一個fib數f[i],然後遞迴判定dfs(n/f[i])是否有解即可.

每次n至少減小一半 每層列舉45個數 最壞45個分支,O(T*45*45*logn).
加個小優化 預處理出可以能是n因子的fib數(應該能晒的只剩10個左右),然後判斷該因子用幾次即可.

實際的複雜度應該比較小

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e2+2;
int T,n,num;
ll f[N],h[N];
bool ans;
void init()
{
    int i;
    f[1]=f[2]=1;
    for(i=3;i<=45;i++)
    {
        f[i]=f[i-1]+f[i-2];
        if(f[i]>1e9)
            break;
     //   cout<<f[i]<<' ';
    }
    num=i;
}
bool dfs(int cur,int n)
{
    if(ans)
        return true;
    if(n==1)
    {
        ans=true;
        return true;
    }
    if(cur>num)
        return false;
    if(dfs(cur+1,n))
        return true;
    int i=cur;
    while(n%h[i]==0)
    {
        if(dfs(cur+1,n/h[i]))
            return true;
        n/=h[i];
    }
    return false;
}
int main()
{
    init();
    cin>>T;
    while(T--)
    {
        ans=false;
        scanf("%d",&n);
        int pn=0;
        for(int i=3;i<=45;i++)
            if(n%f[i]==0)
                h[++pn]=f[i];
        num=pn;
        if(n==1||n==0)
        {
            printf("Yes\n");
            continue;
        }
        ans=dfs(1,n);
        printf(ans?"Yes\n":"No\n");
    }
    return 0;
}

HDU 5163
題意:n個車站 第i個車站和第i+1個車站距離為d[i],
m次詢問,當bus從車站((j-1)%modn+1)出發,第j個人從x[j]坐到y[j]的最短時間. bus開到n後掉頭.
n,m<=1e5,d[i]<=1e9.
分情況討論即可.設bus出發點為s,人的起點終點為[x,y],pre[i]為第i個人距離起點位置.
當x<y時
當s<x 則ans=pre[y]-pre[s].
當x<s<y || s>y 則ans=suf[s]+tot+pre[y]

當x>y時

當s>x || y<s<x || s<y則ans=suf[s]+suf[y]

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5,inf=0x3f3f3f3f;
ll d[N],a[N],pre[N],suf[N];
int main()
{
    int T,n,m;
    cin>>T;
    while(T--)
    {
        scanf("%d%d",&n,&m);
        ll tot=0;
        memset(a,0,sizeof(a));
        memset(pre,0,sizeof(pre));
        memset(suf,0,sizeof(suf));
        for(int i=2;i<=n;i++)
            scanf("%lld",&d[i]),a[i]=a[i-1]+d[i],tot+=d[i];
        for(int i=1;i<=n;i++)
            pre[i]=pre[i-1]+(a[i]-a[i-1]);
        for(int i=n-1;i>=1;i--)
            suf[i]=suf[i+1]+(a[i+1]-a[i]);
        for(int j=1;j<=m;j++)
        {
            int s=(j-1)%n+1;
            int x,y;
            ll ans;
            scanf("%d%d",&x,&y);
            //cout<<s<<' ';
            if(x<y)
            {
                if(s<=x)
                    ans=pre[y]-pre[s];
                else
                    ans=suf[s]+tot+pre[y];
            }
            else
                ans=suf[s]+suf[y];
            printf("%lld\n",ans);
        }
    }
    return 0;
}

題意:長度為n的序列a,操作:交換任意兩個元素,
問操作正好一次的情況下 最多能得到多少種不同的序列? n,a[i]<=1e5.
假如序列元素都不同 則答案為C(n,2) 現在只要扣掉選相同元素的方案數即可.

注意 有相同元素才能得到原來的序列.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
ll b[N];
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        ll n;
        int x;
        memset(b,0,sizeof(b));
        scanf("%I64d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&x),b[x]++;
        ll ans=n*(n-1)/2;
        int flag=0;
        for(int i=1;i<N;i++)
        {
            ans-=(b[i]*(b[i]-1))/2;
            if(b[i]>=2)
                flag=1;
        }
        printf("%I64d\n",ans+flag);
    }
    return 0;
}