寒假训练2021-1-25

先写下昨晚context的题解吧
在这里插入图片描述
数据没拉满,n^2可以过,我讲下nlogn的写法
排序后,用双指针head tail 搞下去 计算贡献

#include <bits/stdc++.h>
using namespace std;

const int mac=1e3+10;

int a[mac];

int main()
{
    
    
    int n,k;
    scanf ("%d%d",&n,&k);
    for (int i=1; i<=n; i++)
        scanf ("%d",&a[i]);
    sort(a+1,a+1+n);
    int head=1,tail=1;
    int ans=1;
    while (tail<=n){
    
    
        while (a[tail]-a[head]<=k && tail<=n) tail++;
        if (a[tail]-a[head]<=k && tail<=n) ans=max(ans,tail-head+1);
        else ans=max(ans,tail-head);
        head++;
    }
    printf("%d\n",ans);
    return 0;
}

在这里插入图片描述
意思是给两个三位数的字符串 每位0–9 他们表示同一个数的不同进制下的表达,要我们确定是哪个进制。
解析:我们枚举一个数的进制,然后二分另外一个数的进制 就OK了

char s1[5];
char s2[5];
ll ex(ll i)
{
    
    
    ll cnt=0;

    for(int rnm=1; rnm<=3; rnm++)
    {
    
    
        cnt=cnt*i+(s1[rnm]-'0');
    }

    return cnt;
}
bool check(ll num,ll bit)
{
    
    

    ll cnt=0;
    for(int rnm=1; rnm<=3; rnm++)
    {
    
    
        cnt=cnt*bit+(s2[rnm]-'0');
    }
    if(cnt>=num)
    {
    
    
        return true;
    }

    return false;


}
signed main()
{
    
    

    ll t;
    read(t);
    while(t--)
    {
    
    
        scanf("%s%s",s1+1,s2+1);

        for(int i=10; i<=15000; i++)
        {
    
    
            ll x=ex(i);
            ll l=9,r=15001;
            while(l<r)
            {
    
    
                ll mid=(l+r)/2;
                if(check(x,mid))
                {
    
    
                    r=mid;

                }
                else
                {
    
    
                    l=mid+1;

                }

            }
            if(l<10||l>15000)
                continue;
            ll op=0;
            op=op*l+(s2[rnm]-'0');
        }
        if(op==x)
        {
    
    
            printf("%lld %lld\n",i,l);
            break;
        }

    }
}


}

在这里插入图片描述
意思是建图以后,询问两个人有没有到达n点的时间是一样的 取最小。n<=16可以暴力搜索,也可以拓扑dp (( 好像跟k短路有关系

ll map1[600][600],map2[600][600];
ll s[600],top,deep[600];
ll dp[20][30000][3];
signed main()
{
    
    


    memset(map1,-1,sizeof map1);
    memset(map2,-1,sizeof map2);
    ll n,m;
    read(n);
    read(m);
    for(int i=1;i<=m;i++){
    
    
    ll u,v,w1,w2;
    read(u);
    read(v);
    read(w1);
    read(w2);
   map1[u][v]=w1;
   map2[u][v]=w2;
   deep[v]++;
    }

    for(int i=1;i<=n;i++)if(deep[i]==0)s[++top]=i;
   dp[1][0][0]=1;
    dp[1][0][1]=1;
    while(top)
    {
    
    

        ll rnm=s[top--];
        for(int i=1; i<=n; i++)
        {
    
    
            if(map1[rnm][i]>0)
           {
    
        deep[i]--;
                if(deep[i]==0) s[++top]=i;
                   
                    //16* 1000
                for(int j=map1[rnm][i]; j<=20000; j++)
                    dp[i][j][0]|=dp[rnm][j-map1[rnm][i]][0];
                for(int j=map2[rnm][i]; j<=20000; j++)
                    dp[i][j][1]|=dp[rnm][j-map2[rnm][i]][1];
            }
        }
    }
    for(int i=0;i<=20000;i++)
    {
    
    
        if(dp[n][i][0]&dp[n][i][1])
        {
    
    
            printf("%lld\n",i);
            return 0;
        }
    }
    puts("IMPOSSIBLE");
    return 0;
}

在这里插入图片描述
n<=500 考虑到只能走两条线,要么是一条直达,要么转机,直接模拟就OK了,注意转机点的序号

ll a[2000][550];
ll num[2200];
ll cost[2200];
ll visu[2200];
ll visv[2200];
map<pair<ll,ll>,ll>sb;
signed main()
{
    
    
    ll u,v,n;
    read(u);
    read(v);
    read(n);
    ll ans=1e18;
    ll op=0;
    for(int i=1; i<=n; i++)
    {
    
    

        read(cost[i]);
        read(num[i]);
        for(int j=1; j<=num[i]; j++)
        {
    
    
            read(a[i][j]);
            sb[ {
    
    i,a[i][j]}]=j;
            if(a[i][j]==u)
            {
    
    
                visu[i]=j;
            }
            if(a[i][j]==v)
            {
    
    
                visv[i]=j;
            }
        }
        if(visu[i]!=0&&visv[i]!=0&&visu[i]<visv[i])
        {
    
    
            ans=min(ans,cost[i]);
            op++;
        }

    }
    for(int i=1; i<=n; i++)
    {
    
    
        if(visu[i]==0)
        {
    
    
            continue;
        }

        for(int j=1; j<=n; j++)
        {
    
    

            if(i==j||visv[j]==0)
            {
    
    
                continue;
            }

            for(int k=visu[i]; k<=num[i]; k++)
            {
    
    
                if(sb[ {
    
    j,a[i][k]}]!=0&&sb[ {
    
    j,a[i][k]}]<visv[j])
                {
    
    

                    ans=min(ans,cost[i]+cost[j]);
                    op++;
                }
            }

        }

    }
    if(op==0)
    {
    
    
        printf("-1");
        return 0;
    }
    printf("%lld\n",ans);


}

在这里插入图片描述
这个我是打表过的QAQ 不会正解,希望大佬可以指点下
----------- 早上写篇题解再刷几个杂题吧 下午复习下

div2 495 做出来4个
AB太水了
C题
给了我们一个长度为n的序列,定义(a,b) 当b的下标>a的下标才合法,求有多少种合法二元组。我们分析,要考虑到重复性,如果正向枚举,那么这个数的所有方案数就是它后面的不同的数的个数,而且每个数只能算一次,那么先倒着预处理一次后缀 sum i 表示 n到i+1 有多少个不同的数


 
const int maxn = 1e5 + 7;
int n;
set<int> s, t;
int a[maxn], sum[maxn];
signed main() {
    
    
    ll n;
    read(n);
    for(int i = 0; i < n; i++) {
    
    
   read(a[i]);
    }
    for(int i = n - 1; i >= 0; i--) {
    
    
        sum[i] = s.size();
        if(!s.count(a[i])) {
    
    
            s.insert(a[i]);
        }
    }
    long long ans = 0;
    for(int i = 0; i < n; i++) {
    
    
        if(t.count(a[i])) continue;
        t.insert(a[i]);
        ans += sum[i];
    }
   printf("%lld",ans);
    return 0;
}

D题 思维+模拟 题意自己慢慢看吧,考虑到扩散,我们可以得知最多可以扩散多少圈,那么可以确定0点的x 或者y 坐标, 顺着模拟check吧

猜你喜欢

转载自blog.csdn.net/weixin_45948940/article/details/113104872
今日推荐