2019-10-9

T1

一道0,1背包的题。。看这个数是否放入背包。。。

这个是标程

/*
选出来的每个整数相当于重量w[i];每个整数的因数和相当于价值c[i]
背包最大容量为s; 
f[i][x]表示考虑了前i个数,当前得到的和为x时(背包已装容量),得到的因数和(价值)最大值 
*/ 

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

int m,s,f[1005][1005];
int ysh[1005];            //ysh[i]表示i的因数和,可以先预处理出来

void makesum(int m)       //求出1...m每个数的因数和 
{
    ysh[1]=0;
    for(int i=2;i<=m;i++)
    {
        s=1;
        for(int j=2;j<=i/2;j++)
            if(i%j==0) s=s+j;
        ysh[i]=s;
    }
}

int main() 
{
    freopen("sum.in", "r", stdin);
    freopen("sum.out", "w", stdout);
  
    scanf("%d", &m);
    makesum(m);                //预处理1...m每个数的因数和  
    
    memset(f,0,sizeof(f)); 
    
    for(int i=1; i<=m;++i)     // 0/1背包 
        for(int x=1;x<=m;x++)
           if(x>=i) 
              f[i][x]=max(f[i-1][x-i]+ysh[i],f[i-1][x]); //第i个数可以选择装进背包 
           else
              f[i][x]=f[i-1][x];                         //第i个数不能装进背包 
    printf("%d\n",f[m][m]);                         
    return 0;
}

这个是打表代码

/*
选出来的每个整数相当于重量w[i];每个整数的因数和相当于价值c[i]
背包最大容量为s; 
f[i][x]表示考虑了前i个数,当前得到的和为x时(背包已装容量),得到的因数和(价值)最大值 
*/ 
#include <bits/stdc++.h> 
using namespace std;

int m,f[1005][1005];

const int ysh[1001] = {0, 0, 1, 1, 3, 1, 6, 1, 7, 4, 8, 1, 16, 1, 10, 9, 15, 1, 21, 1, 22, 11, 14, 1, 36, 6, 16, 13, 28, 1, 42, 1, 31, 15, 20, 13, 55, 1, 22, 17, 50, 1, 54, 1, 40, 33, 26, 1, 76, 8, 43, 21, 46, 1, 66, 17, 64, 23, 32, 1, 108, 1, 34, 41, 63, 19, 78, 1, 58, 27, 74, 1, 123, 1, 40, 49, 64, 19, 90, 1, 106, 40, 44, 1, 140, 23, 46, 33, 92, 1, 144, 21, 76, 35, 50, 25, 156, 1, 73, 57, 117, 1, 114, 1, 106, 87, 56, 1, 172, 1, 106, 41, 136, 1, 126, 29, 94, 65, 62, 25, 240, 12, 64, 45, 100, 31, 186, 1, 127, 47, 122, 1, 204, 27, 70, 105, 134, 1, 150, 1, 196, 51, 74, 25, 259, 35, 76, 81, 118, 1, 222, 1, 148, 81, 134, 37, 236, 1, 82, 57, 218, 31, 201, 1, 130, 123, 86, 1, 312, 14, 154, 89, 136, 1, 186, 73, 196, 63, 92, 1, 366, 1, 154, 65, 176, 43, 198, 29, 148, 131, 170, 1, 316, 1, 100, 141, 203, 1, 270, 1, 265, 71, 104, 37, 300, 47, 106, 105, 226, 31, 366, 1, 166, 75, 110, 49, 384, 39, 112, 77, 284, 31, 234, 1, 280, 178, 116, 1, 332, 1, 202, 153, 218, 1, 312, 53, 184, 83, 194, 1, 504, 1, 157, 121, 190, 97, 258, 33, 232, 87, 218, 1, 476, 35, 130, 177, 255, 1, 270, 45, 328, 129, 134, 1, 456, 59, 214, 93, 208, 1, 450, 1, 286, 175, 140, 97, 396, 1, 142, 137, 440, 1, 294, 1, 220, 195, 218, 49, 531, 18, 250, 101, 226, 1, 390, 65, 274, 183, 152, 37, 568, 51, 154, 105, 316, 67, 396, 1, 364, 107, 266, 1, 528, 1, 160, 309, 244, 1, 330, 41, 442, 111, 254, 37, 523, 109, 166, 113, 302, 55, 534, 1, 256, 161, 170, 73, 656, 1, 211, 117, 416, 43, 438, 57, 316, 231, 176, 1, 492, 1, 394, 209, 404, 1, 366, 77, 274, 219, 182, 1, 810, 20, 184, 169, 420, 79, 378, 1, 376, 177, 314, 61, 524, 1, 274, 249, 344, 43, 582, 1, 460, 131, 194, 1, 636, 191, 196, 185, 298, 1, 618, 41, 463, 135, 200, 85, 696, 1, 202, 241, 561, 1, 414, 45, 310, 321, 314, 49, 672, 1, 346, 141, 316, 67, 522, 89, 466, 143, 302, 1, 924, 1, 214, 201, 386, 133, 438, 69, 328, 243, 362, 1, 808, 1, 334, 285, 334, 43, 450, 1, 640, 300, 314, 1, 620, 95, 226, 153, 568, 1, 759, 53, 346, 155, 230, 217, 744, 1, 232, 261, 548, 1, 690, 1, 466, 303, 236, 1, 806, 75, 394, 161, 428, 55, 486, 145, 532, 225, 242, 1, 1032, 51, 244, 285, 447, 103, 606, 1, 442, 167, 536, 1, 684, 47, 346, 441, 496, 79, 510, 1, 592, 171, 254, 1, 1056, 107, 358, 225, 388, 1, 786, 81, 511, 287, 260, 109, 716, 59, 394, 177, 740, 1, 648, 1, 400, 467, 266, 49, 960, 24, 442, 249, 588, 55, 546, 113, 484, 183, 272, 145, 1140, 1, 274, 185, 590, 115, 798, 1, 418, 257, 566, 49, 888, 87, 280, 357, 424, 1, 690, 57, 928, 303, 284, 1, 780, 119, 286, 401, 512, 1, 870, 1, 604, 195, 434, 169, 1075, 1, 343, 197, 680, 91, 594, 65, 526, 507, 296, 1, 1008, 51, 490, 201, 586, 1, 846, 269, 454, 203, 410, 1, 1260, 1, 454, 281, 460, 193, 618, 1, 652, 351, 506, 61, 1026, 1, 310, 393, 824, 1, 630, 1, 724, 339, 314, 97, 1112, 156, 316, 333, 478, 55, 1242, 1, 568, 215, 320, 133, 876, 161, 442, 297, 890, 1, 654, 1, 700, 411, 434, 1, 1167, 71, 652, 373, 496, 1, 666, 137, 646, 305, 494, 1, 1356, 1, 334, 345, 596, 295, 816, 53, 508, 227, 554, 73, 1344, 1, 340, 565, 605, 1, 690, 105, 940, 231, 470, 1, 1136, 143, 514, 233, 676, 67, 1038, 1, 526, 555, 350, 145, 1104, 59, 352, 237, 1036, 1, 978, 57, 820, 447, 356, 109, 972, 1, 586, 329, 638, 55, 1014, 293, 544, 243, 362, 1, 1698, 111, 421, 245, 550, 205, 870, 1, 952, 364, 602, 61, 1004, 1, 370, 633, 776, 79, 900, 1, 856, 379, 554, 1, 1176, 155, 376, 345, 764, 115, 1122, 1, 736, 255, 506, 157, 1484, 1, 382, 393, 1040, 1, 774, 117, 580, 639, 386, 73, 1276, 1, 958, 261, 586, 1, 942, 217, 694, 439, 392, 61, 1572, 83, 514, 417, 983, 163, 798, 1, 598, 267, 650, 121, 1548, 75, 400, 501, 604, 1, 1122, 65, 1153, 369, 404, 85, 1100, 347, 538, 273, 722, 1, 1368, 1, 868, 275, 554, 169, 1416, 63, 412, 637, 944, 1, 834, 1, 736, 663, 614, 1, 1356, 1, 682, 281, 946, 193, 846, 173, 844, 443, 422, 1, 2040, 30, 424, 285, 640, 253, 1026, 217, 826, 287, 824, 61, 1164, 1, 634, 705, 764, 1, 1158, 1, 988, 483, 434, 1, 1656, 179, 436, 361, 924, 91, 1290, 81, 778, 401, 566, 373, 1196, 1, 442, 297, 1352, 1, 1341, 1, 880, 555, 446, 1, 1392, 135, 730, 561, 676, 67, 906, 185, 1144, 447, 452, 61, 1921, 71, 610, 505, 806, 187, 918, 1, 688, 417, 1106, 1, 1568, 95, 460, 573, 694, 139, 1242, 1, 1240, 311, 464, 85, 1764, 253, 466, 425, 962, 1, 1374, 209, 706, 315, 470, 361, 1794, 1, 694, 317, 1076, 1, 954, 65, 916, 975, 638, 1, 1292, 87, 910, 321, 1208, 1, 1152, 197, 724, 483, 482, 145, 2088, 32, 634, 441, 730, 199, 1338, 1, 1027, 471, 794, 1, 1576, 147, 490, 761, 946, 1, 990, 101, 1414, 449, 494, 1, 1536, 203, 634, 549, 972, 67, 1818, 1, 1024, 335, 734, 205, 1356, 1, 502, 521, 1340};
//ysh[i]表示i的因数和,先打表打出每个整数的因数和 

int main() 
{
    freopen("sum.in", "r", stdin);
    freopen("sum.out", "w", stdout);
    f[0][0]=0;
    
    scanf("%d", &m);
    for(int i=1; i<=m;++i)     // 0/1背包 
        for(int x=1;x<=m;x++)
           if(x>=i) 
              f[i][x]=max(f[i-1][x-i]+ysh[i],f[i-1][x]); //第i个数可以选择装进背包 
           else
              f[i][x]=f[i-1][x];                         //第i个数不能装进背包 
    printf("%d\n",f[m][m]);                         
    return 0;
}

这个是我的代码(所以我都不知道我的dp是什么意思。。。居然是一维的我惊了)

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define rg register
using namespace std;

inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0' || ch>'9')
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0' && ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}

int f[1010];
int tag[1010][1010];
int yinshu[1010][1010];
int flag[1010];
int n;
int main()
{
    freopen("sum.in","r",stdin);
    freopen("sum.out","w",stdout);
    n=read();
    f[1]=0;f[2]=1;
    tag[2][1]=1;
    for(rg int i=1;i<=n;i++)
        yinshu[i][1]=1;
    for(rg int i=2;i<=n;i++)
    {
        yinshu[i][i]=1;
        for(rg int j=i*2;j<=n;j+=i)
            yinshu[j][i]=1;
    }
    
    for(rg int i=3;i<=n;i++)
    {
        int a[2]={0,0},b[3]={0,0,0},c[3]={0,0,0};
        for(rg int j=1;j<i;j++)
        {
            /*
            if(f[j]>f[i])
                for(int k=1;k<=j;k++)
                    tag[i][k]=tag[j][k];
            f[i]=max(f[i],f[j]);
            */
            if (f[j]>a[0])
                a[0]=j,a[1]=f[j];
        }
        for(rg int j=1;j<i;j++)
        {
            int k=i-j;
            if(k==j || tag[j][k])
                continue;
            int sum=0;
            for(rg int nm=1;nm<=k/2;nm++)
                sum+=(yinshu[k][nm]*nm);
            if(f[j]+sum>b[2])
            {
                b[0]=j;b[1]=k;b[2]=f[j]+sum;
//                for(int nm=1;nm<=j;nm++)
//                    tag[i][nm]=tag[j][nm];
//                tag[i][k]++;
            }
                
//            f[i]=max(f[i],f[j]+f[k]);
        }
        int sum=0;
        for(rg int j=1;j<i;j++)
            sum+=(yinshu[i][j]*j);
        if(sum>f[i])
        {
            c[0]=i;c[1]=sum;
        }
        if(c[1]>=b[2] && c[1]>=a[1])
            tag[i][c[0]]++,f[i]=c[1];
        else if(a[1]>=c[1] && a[1]>=b[2])
        {
            for(rg int k=1;k<=a[0];k++)
                tag[i][k]=tag[a[0]][k];
            f[i]=a[1];
        }
        else
        {
            for(rg int nm=1;nm<=b[0];nm++)
                    tag[i][nm]=tag[b[0]][nm];
            tag[i][b[1]]++;
            f[i]=b[2];
        }
//        f[i]=max(f[i],sum);
    }
    printf("%d",f[n]);
}

T2

这道题首先二分答案(即平均值) 然后判断这个答案是否合法

如果合法则继续向上二分 否则向下二分

这个都很好理解

关键是如何判断合法呢 这里是采用了单调队列

首先把每个数减去当前的平均值后求出前缀和

枚举右端点i 则左端点的范围为i-L~i-R

然后使用一个递增的单调队列 如果队首不在范围内 就弹出

如果队尾大于正要加入的数 就弹出,直到小于等于

如果当前i节点的前缀和-队首的值>0,返回true,否则返回false

(这里就可以理解为什么要维护递增的单调区间了,因为要减去尽量小的值,这个式子总体的值才大)

这个样子就可以了

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
using namespace std;
const double eps=1e-9;
const int maxn=1e5;
int n,l,r;
double maxa,a[maxn],b[maxn],c[maxn];
int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0' || ch>'9')
    {
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(ch>='0' && ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}

bool check(double x)
{
    double sum[maxn],que[maxn];
    int head=1,tail=0,pos[maxn];
    for(int i=1;i<=n;i++)
        sum[i]=a[i]+sum[i-1]-x;
    for(int i=l;i<=n;i++)
    {
        while(head<=tail && que[tail]>=sum[i-l])
            tail--;
        while(head<=tail && pos[head]+r<i)
             ++head;
        que[++tail]=sum[i-l];
        pos[tail]=i-l;
        if(sum[i]-que[head]>=0)
            return true;
    }
    return false;
}

int main()
{
    n=read();l=read();r=read();
    for(int i=1;i<=n;++i)
    {
        scanf("%lf",&a[i]);
        if(a[i]-maxa>eps)
            maxa=a[i];
    }
    double l=0,r=maxa,ans;
    while(r-l>eps)
    {
        double mid=(l+r)/2;
        if(check(mid))
        {
            ans=mid;
            l=mid;
        }
        else
        {
            r=mid;
        }
    }
    printf("%.4f",ans);
}

T3

这道题相当于找一个最小生成树,再加边使得有n个点n条边,这样就可以保证每个点入度都为1

使用kruskal算法,因为这个算法是先加入边权较小的边

注意这个题有可能是基环树森林哦,所以我们需要判断每个点它(它父亲)所在的树是否有环

如果当前正要加入的边连接了两个有环树 continue

如果当前加入的边在一个树内 就会形成一个有环树

如果是连接两个无环树 没有影响

如果连接一个无环树 一个有环树 就会形成一棵有环树

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#define int long long 
using namespace std;
const int maxn=5*1e5+100;
struct node{
    int from,to,val;
    inline bool operator <(const node &x)const{
        return val<x.val;
    }
    #define from(x) edge[x].from
    #define to(x) edge[x].to
    #define val(x) edge[x].val
}edge[maxn];
int n,m,par[maxn],ring[maxn];
int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0' || ch>'9')
    {
        if(ch=='-')    
            f=-1;
        ch=getchar();
    }
    while(ch>='0' && ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}

int getfather(int x)
{
    if(par[x]==x)    return x;
    ring[par[x]]=max(ring[par[x]],ring[x]);
    par[x]=getfather(par[x]);
    return par[x];
}

signed main()
{
    n=read();m=read();
    for(int i=1;i<=m;i++)
    {
        from(i)=read();to(i)=read();val(i)=read();
    }
        
    sort(edge+1,edge+1+m);
    int f1,f2,ans=0;
    for(int i=1;i<=n;i++)    par[i]=i;
    for(int i=1;i<=m;i++)
    {
        f1=getfather(from(i));
        f2=getfather(to(i));
        if(ring[f1] && ring[f2])//如果两棵树都是有环树,则跳过,因为如果再加边就会使得每个边的入度大于1 
            continue;
        if(f1==f2 || ring[f1] || ring[f2])//在一个联通块内加边会形成环,一个无环树与一个有环树形成一个有环树 
            ring[f1]=ring[f2]=1;
        ans+=val(i);
        par[f1]=f2;
        
    }
    printf("%lld",ans);
}

在然后就是可爱的费用流了(费用流会爆空间,只能得60分,呜呜呜100多行呢考试的时候写了,我好难受只有60分)

(疯狂暗示这是考试代码)

#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring>
#define int long long 
using namespace std;
const int maxn=850100;
const int inf=0x3f3f3f3f;
int first[maxn<<1],next[maxn<<1],to[maxn<<1],flow[maxn<<1],cost[maxn<<1];
int tot=1;
int n,m,s,t;
int d[maxn<<1],maxflow,ans,book[maxn<<1],pre[maxn<<1];
int incf[maxn<<1],x,y,c;

int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0' || ch>'9')
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0' && ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}

void add(int u,int v,int w,int f)
{
    tot++;
    next[tot]=first[u];
    first[u]=tot;
    to[tot]=v;
    flow[tot]=w;
    cost[tot]=f;
}

bool spfa()
{
    queue<int> q;
    memset(book,0,sizeof(book));
    for(int i=1;i<=n+m+1;i++)
        d[i]=inf;
    q.push(s);
    d[s]=0;book[s]=1;incf[s]=0x3f3f3f3f;
    while(!q.empty())
    {
        int x=q.front();
        book[x]=0;
        q.pop();
        for(int i=first[x];i;i=next[i])
        {
            int y=to[i];
            if(flow[i] && d[y]>d[x]+cost[i])
            {
                d[y]=d[x]+cost[i];
                incf[y]=min(incf[x],flow[i]);
                pre[y]=i;
                if(book[y]==0)    book[y]=1,q.push(y);
            }
        }
    }
    if(d[t]==inf)
        return false;
    return true;
}

void update()
{
    int cxk=t;
    while(cxk!=s)
    {
        int i=pre[cxk];
        flow[i]-=incf[t];
        flow[i^1]+=incf[t];
        cxk=to[i^1];
    }
    maxflow+=incf[t];
    ans=ans+d[t]*incf[t];
}

signed main()
{
    freopen("trade.in","r",stdin);
    freopen("trade.out","w",stdout);
    n=read();m=read();
    s=0;t=n+m+1;
    for(int i=1;i<=m;i++)
    {
        add(s,i,1,0);
        add(i,s,0,0);
        x=read();y=read();c=read();
        add(i,x+m,1,c);
        add(x+m,i,0,-c);
        add(i,y+m,1,c);
        add(y+m,i,0,-c);
    }
    for(int i=1;i<=n;i++)
    {
        add(i+m,t,1,0);
        add(t,i+m,0,0);
    }
    while(spfa()) update();
    if(maxflow==n)
        printf("%lld",ans);
    else printf("No");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值