2016.7.8 做的题~~的汇总 【poj】1742 bzoj【2096】poj【1182】tyvj【1391】poj【2492】

应该会持续更新完今天写的~~

第一道,poj 1742 男人八题之一【可是po主是个萌萌哒的妹子~~~】

按说这是一道多重背包 加单调队列 优化的题 可是 朕用了 什么奇奇怪怪自己的方法,虽然wa了一次,但是还是没能tle???

是这么想的
循环每种币值,然后再循环价格,如果这个还没拼过,它可以由拼出来的转移过来,并且面值不能大于拥有的数量。恩就是这样

一开始想了个错的【【统计了一下所有钱币的数目然后转移加1但是 其实品的方案又很多种,你又不能这么记了。。。】】
上代码!!!!

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m;
int w[101];
int c[101];
int num[100005];   //num统计 的是 当前面值 用了几张 不用统计 一共用了几张,因为 有可能 凑成的方法不一样 
int vis[100005];
int main()
{
    while(scanf("%d%d",&n,&m) && n!=0 && m!=0)
    {
        memset(w,0,sizeof(w));
        memset(c,0,sizeof(c));
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&w[i]);
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&c[i]);
        }
        int cnt=0;
        memset(vis,0,sizeof(vis));
        vis[0]=1;
        for(int i=1;i<=n;i++)
        {
            memset(num,0,sizeof(num));
            for(int j=w[i];j<=m;j++)
            {
                if(!vis[j] && vis[j-w[i]] && num[j-w[i]]+1<=c[i])   //vis[j-w[i]]保证了 前一种能凑成所以  币值不会超 
                {
                    num[j]=num[j-w[i]]+1;
                    printf("id is %d,val is %d,num is %d\n",w[i],j,num[j]);
                    vis[j]=1;
                    cnt++;
                }
            }
        }
        printf("%d\n",cnt);
    }

}
/*
3 10
1 2 4 2 1 1
2 5
1 4 2 1
100 100000
2753 23850 78826 76015 82258 2875 9510 62449 37906 75392 7823 19447 17253
12571 57217 66434 97242 47551 40323 72899 14697 1399 81251 57900 25190 45590
94071 68477 10082 67472 56318 18265 64794 85219 77138 95537 27968 86715 56437
18417 6205 6682 77321 11135 25641 74087 53250 49579 95416 49504 72545 17202
2805 73705 75722 77388 11810 84569 40207 98880 572 51537 77363 23819 25157
73699 8744 89659 22913 89405 42796 66867 85384 28612 25656 53238 14200 82294
66734 36245 81715 70882 12802 49524 17568 22292 55323 74886 31722 52457 41995
82688 20611 11955 32356 30652 25390 82318 91741 12958 68 88 81 41 55 20 40 51
78 48 16 70 3 32 3 41 72 81 56 74 62 99 67 89 34 43 77 59 58 23 28 78 100 15 5
17 48 51 38 73 59 66 82 49 59 56 51 6 85 71 19 74 71 16 74 11 33 16 77 70 55
39 58 55 10 94 25 94 4 10 99 6 26 4 59 71 51 26 100 67 21 28 47 63 7 57 90 91
26 24 91 58 67 10 3 6 55 65 41 55 
0 0
*/

然后有时间要复习一下 多重背包 怎么写~~~

第二道 bzoj 2096
这是道权限题虽然楼主不是权限狗。【我怎么测得?】你猜啊!

懒猴说说这道题:
这个要用两个单调队列~~,一个维护 区间最大 值,一个维护区间最小值,

再然后 直接 枚举右端点 更新ans找最长的。。就ok了:q)

单调队列还是不太会写。。。听从杨贵妃的劝告 以后 少看题解~自己yy代码。。。记住了

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,k;
int ans;
int a[3000005];
int q1[3000005];    //维护区间最大值 
int q2[3000005];    //维护区间最小值 
int main()
{
    scanf("%d%d",&k,&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    int l1=1,l2=1,r1=0,r2=0;
    int t=1;
    for(int i=1;i<=n;i++)
    {
        while(l1<=r1 && a[i] >= a[q1[r1]]) r1--;
        while(l2<=r2 && a[i] <= a[q2[r2]]) r2--;
        q1[++r1]=i;
        q2[++r2]=i;
        while(a[q1[l1]]-a[q2[l2]] >k)      //不符合条件! 
        {
            if(q1[l1] <q2 [l2]) t=q1[l1]+1,l1++;
            else  t=q2[l2]+1,l2++;
        }
        ans=max(ans,i-t+1); 
    }
    printf("%d\n",ans); 
    return 0;
} 

截止 14:48 是这样

第四道:
poj 1182 单独开了一个
戳戳戳

第五道:
tyvj1391
戳戳戳

这道题,在经过 本宝宝 的机智和哀家的不懈努力的教下终于出炉了,所以鸣谢!!!@SiriusRen

所以 我们来说一说这道题
题目干货的意思就是
在保证最小生成树唯一的情况下,生成一个完全图。

那么我们可以发现 在将最小生成树建立的过程中 其实使用到了并查集。

然后在观察我们可以发现:
如果把一个大小为x的最小生成树连到一个大小为y的那么 要构成联通图需要 x*y条,蓝后其中还包括 一条连 两棵树的边所以会出现 x*y-1条新的边

那么问题就很好解决了 我们可以 统计一下 每次加边的时候两棵树的大小 乘一下当前边加一嘞! 注意哦 最小生成树吗所以要有变得排序

另外本宝宝第一道 读入优化的题这题可能不明显。。。

好吧看代码吧

#include<cstdio>
#include<algorithm>
#include<cstring>
//by mars_ch
using namespace std;
int n;
__int64 ans;
struct data
{
    int x,y,w;
}e[6005];
int f[6005];
int son[6001];
int read()
{
    int x=0;
    char p=getchar();
    while(p<'0' || p>'9') p=getchar();
    while(p>='0' && p<='9') x=x*10+p-'0',p=getchar();
    return x; 
} 
bool cmp(data a,data b)
{
    return a.w<b.w;
}
int find(int x)
{
    if(f[x]==x) return x;
    f[x]=find(f[x]);
    return f[x];
}
int main()
{
    int t=read();
    while(t--)
    {
        n=read();
        for(int i=1;i<n;i++)
        {
            int x,y,w;
            x=read();y=read();w=read();
            e[i].x=x;e[i].y=y;e[i].w=w;
        }
        sort(e+1,e+n,cmp);
        for(int i=1;i<=n;i++)
        {
            f[i]=i;
            son[i]=1;
        }
        ans=0;
        for(int i=1;i<n;i++)
        {
            int fx=find(e[i].x);
            int fy=find(e[i].y);

            if(fx!=fy)
            {
                ans+=(son[fx]*son[fy]-1)*(e[i].w+1);
                f[fx]=fy;
                son[fy]+=son[fx];
            }
        }
        printf("%I64d\n",ans);
    }
    return 0;
}

第七道:
还是个并查集,大概写的没错,但是为什么最后错了呢? 初始化的位置 不对。
感谢哀家救了我于水火之中

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
//by mars_ch
int T; 
int n,m;
bool flag;
int f[1000005];
int re[1000005];
void init()
{
    memset(re,0,sizeof(re));
    for(int i=1;i<=n;i++)
    {
        f[i]=i;
    }
    flag=0;
}
int find(int x)
{
    if(f[x] == x) return x;
    int tmp=find(f[x]);
    re[x]=(re[x]+re[f[x]])%2;
    return f[x]=tmp;
}
int main()
{
    scanf("%d",&T);
    for(int cases=1;cases<=T;cases++)
    {

        scanf("%d%d",&n,&m);
        init();
        for(int i=1;i<=m;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            int fa=find(a);
            int fb=find(b);
            if(fa == fb)
            {
                if(re[a] == re[b])
                {
                    flag=1;
                }
            }
            else
            {
                f[fa]=fb;
                re[fa]=(re[a]-re[b]+1)%2;
            }
        }
        printf("Scenario #%d:\n",cases);
        if(flag)
        {
            printf("Suspicious bugs found!\n\n");
        }
        else printf("No suspicious bugs found!\n\n");
    }
    return 0;
}

或许该睡觉了。。。。明天将数学。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值