【2016 ACM/ICPC Asia Regional Qingdao Online】

来源:互联网 发布:php直播间源码 编辑:程序博客网 时间:2024/05/18 02:21

[ HDU 5878 ] I Count Two Three

考虑极端,1e9就是2的30次方,3的17次方,5的12次方,7的10次方。

而且,不超过1e9的乘积不过5000多个,于是预处理出来,然后每次二分找就可以了。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/*
TASK:I Count Two Three 2^a*3^b*5^c*7^d的最小的大于等于n的数是多少
LANG:C++
URL:http://acm.hdu.edu.cn/showproblem.php?pid=5878
*/
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define ll long long
usingnamespace std;
constint N=32;
constll M=1e9+1;
inttw,th,fi,se,t,n;
ll two[N]={1},three[N]={1},five[N]={1},seven[N]={1};
ll ans[7000],cnt;
intmain() {
    for(inti=1;two[i-1]<M;i++,tw++)
        two[i]=two[i-1]*2;
    for(inti=1;three[i-1]<M;i++,th++)
        three[i]=three[i-1]*3;
    for(inti=1;five[i-1]<M;i++,fi++)
        five[i]=five[i-1]*5;
    for(inti=1;seven[i-1]<M;i++,se++)
        seven[i]=seven[i-1]*7;
         
    for(inti=0;i<tw;i++)
    for(intj=0;three[j]*two[i]<M&&j<th;j++)
    for(intk=0;five[k]*three[j]*two[i]<M&&k<fi;k++)
    for(intg=0;seven[g]*five[k]*three[j]*two[i]<M&&g<se;g++)
        ans[cnt++]=two[i]*three[j]*five[k]*seven[g];
         
    sort(ans,ans+cnt);
     
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        printf("%lld\n",ans[lower_bound(ans,ans+cnt,n)-ans]);
    }
}

[ HDU 5879 ] Cure

当n很大时,答案趋于1.64493,于是n小时输出预处理的,大时答案就是1.64493。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/*
TASK:求∑1/k^2 k=1到n
LANG:C++
URL:http://acm.hdu.edu.cn/showproblem.php?pid=5879
*/
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define ll long long
#define N 115000
usingnamespace std;
charn[1000000];
doubleans[N];
voidinit(){
    for(ll i=1;i<N;i++)
        ans[i]=ans[i-1]+1.0/(i*i);
}
doubleget(){
    inta=0,len=0;
    for(inti=0;n[i]&&len<7;i++,len++)
        a=a*10+n[i]-'0';
    if(len==7||a>=N)return1.64493;
    returnans[a];
}
intmain() {
    init();
    while(~scanf("%s",n)){
        printf("%.5f\n",get());
        memset(n,0,sizeofn);
    }
}

[ HDU 5881 ] Tea

注意最后可以留1升水,所以2升2升地倒向上取整是((r-1)+1)/2 就是r/2,l==0时,先倒了1次1,所以r还要-1;

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*
TASK:壶里有L到R区间的水,倒俩杯里,倒完时相差不超过1,壶里最多可以余1,求最少多少次一定能倒完。
LANG:C++
URL:http://acm.hdu.edu.cn/showproblem.php?pid=5881
*/
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define ll long long
usingnamespace std;
ll l,r,ans;
intmain() {
    while(~scanf("%lld%lld",&l,&r)){
        if(r<=1)
            ans=0;
        elseif(r<=2)
            ans=1;
        elseif(l==r)
            ans=2;
        elseif(l==0)//第一次倒l/2+0.5,第二次倒l/2+1.5,然后2、2、2、如果l==0,不如第一次就倒1,然后2、2、2
            ans=1+(r-1)/2;
        else{
            r-=l+2;//前两次倒的
            ans=2+r/2;
        }
        printf("%lld\n",ans);
    }
    return0;
}

[ HDU 5882 ] Balanced Game

n为奇数就是有n-1个度,只要保证n-1为偶数就存在,所以n为奇数就存在。

[ HDU 5883 ] The Best Path

如果点的度为奇数的有2个或0个,那么存在路,2个则从一个度为奇数的点出发,另一个点结束,起点和终点异或了(du[i]+1)/2次,其它点异或了du[i]/2次。都是偶数的点则以一个点为起点,最后回到它,那么这个点多异或一次。因为du为偶数时,(du[i]+1)/2和du[i]/2相等,所以循环里不用判断了。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/*
TASK:The Best Path 求经过连通图的所有边一次且经过点异或起来值最大的路的异或值
LANG:C++
URL:http://acm.hdu.edu.cn/showproblem.php?pid=5883
*/
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define ll long long
#define N 100005
usingnamespace std;
intt,n,m,a[N];
intdu[N];
voidsolve(){
    intnum=0;
    for(inti=1;i<=n;i++)
        if(du[i]%2)
            num++;
    if(num!=2&&num){
        puts("Impossible");
        return;
    }
    intans=0;
    for(inti=1;i<=n;i++)
        for(intj=1;j<=(du[i]+1)/2;j++)
            ans^=a[i];
    if(!num){
        inttans=ans;
        for(inti=1;i<=n;i++)
            ans=max(ans,tans^a[i]);
    }
    printf("%d\n",ans);
}
intmain() {
    scanf("%d",&t);
    while(t--){
        memset(du,0,sizeofdu);
        scanf("%d%d",&n,&m);
        for(inti=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(inti=1;i<=m;i++){
            intu,v;
            scanf("%d%d",&u,&v);
            du[u]++;
            du[v]++;
        }
        solve();
    }
    return0;
}

[ HDU 5884 ] Sort

做过类似的,主要要注意的是不能刚好每次k个时,要第一次来合并不足k个的,两个单调队列,一个是合并后的,一个是未合并的,每次合并时选两个队列里小的那个。

二分判断的时候,如果答案已经超过cost,就一定不行了。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/*
TASK:Sort 合并数列,每次合并花费数列大小之和,求总代价不超过T的最小的每次最多合并个数k。
LANG:C++
URL:http://acm.hdu.edu.cn/showproblem.php?pid=5884
*/
#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 100005
#define ll long long
usingnamespace std;
ll n,t,p;
ll a[N],h[N],cost;//h是合并后的优先队列
ll solve(intk)
{
    memset(h,0,sizeofh);
    t=(n-1)/(k-1);//需要减少n-1堆,每次减少k-1堆能合并几次。
    p=(n-1)%(k-1);//还要减少p堆(p<k-1)
    for(inti=0; i<=p; i++)//那就合并前p+1堆
        h[0]+=a[i];
    inttop=p+1,htop=0;
    ll ans=p?h[0]:0;//第一次有合并则加上合并的代价。
    for(inti=1; i<=t; i++)//k个k个合并t次
    {
        for(intj=0; j<k; j++)//合并k个
            if(htop>=i||a[top]<h[htop]&&top<n)//如果合并队列里没有了可选的了,或者未合并队列的更小,则取未合并队列的。
                h[i]+=a[top++];
            else
                h[i]+=h[htop++];
        ans+=h[i];//累加答案
        if(ans>cost)
            return0;
    }
    if(ans>cost)
        return0;
    return1;
}
intmain()
{
    intt;
    scanf("%d",&t);
    while(t--){
        scanf("%lld%lld",&n,&cost);
        for(inti=0; i<n; i++)
            scanf("%lld",&a[i]);
        sort(a,a+n);
        intl=2,r=n;
        while(l<r) {
            intm=(l+r)/2;
            if(solve(m))
                r=m;
            else
                l=m+1;
        }
        printf("%d\n",l);
    }
    return0;
}

[ HDU 5887 ]  Herbs Gathering

用map来存状态转移,还要优化一下,去掉体积更大且价值更小的状态。 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/*
TASK:Herbs Gathering 容量很大,价值也很大,数量少的01背包问题。
LANG:C++
URL:http://acm.hdu.edu.cn/showproblem.php?pid=5887
*/
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <map>
#define ll long long
usingnamespace std;
constint N=108;
map<ll,ll>mm[N];
map<ll,ll>::iterator it,ij;
intn,t;
ll a[N],b[N];
intmain() {
    while(~scanf("%d%d",&n,&t)){
        for(inti=0;i<=n;i++)
        mm[i].clear();
        mm[0][0]=0;
        for(inti=1;i<=n;i++){
            scanf("%lld%lld",&a[i],&b[i]);
            mm[i][0]=0;
        }
         
        for(inti=1;i<=n;i++){
            for(it=mm[i-1].begin();it!=mm[i-1].end();it++){
                if(it->first+a[i]<=t)
                {
                    if(mm[i].count((it->first)+a[i]))
                        mm[i][(it->first)+a[i]]=max(it->second+b[i],mm[i][(it->first)+a[i]]);
                    elsemm[i][(it->first)+a[i]]=it->second+b[i];
                }
                if(mm[i].count((it->first)))
                    mm[i][(it->first)]=max(it->second,mm[i][it->first]);
                else
                    mm[i][it->first]=it->second;
                 
                ll rm=0;
                for(ij=mm[i].begin();ij!=mm[i].end();ij++){
                    //printf("%d [%lld %lld]:[%lld %lld]\n",i,ij->first,ij->second,it->first,it->second);
                    if(ij->first>it->first &&ij->second<it->second)
                        rm=ij->first;
                    elseif(ij->first<it->first && ij->second>it->second)
                        rm=it->first;
                }
                if(rm)
                    mm[i].erase(rm);
            }
        }
        ll ans=0;
        for(it=mm[n].begin();it!=mm[n].end();it++)
            ans=max(ans,(it->second));
         
        printf("%lld\n",ans);
    }
     
}

[ HDU 5889 ] Barricade

先用bfs求出最短路(经过最少点到达),之后把最短路的边加到网络流的边里,注意这里的权值是给的w,用isap跑网络流比较保险,不容易超时。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
TASK:Barricade 求最短路的最小割
LANG:C++
URL:http://acm.hdu.edu.cn/showproblem.php?pid=5889
*/
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define ll long long
#define N 1005
#define M 40010
#define inf 0x3f3f3f3f
usingnamespace std;
structedge{
    intto,next,cap,flow;
}e[M];
inthead[N],cnt;
intgap[N],dep[N],cur[N];
voidinit(){
    cnt=0;
    memset(head, -1,sizeof head);
}
voidadd(int u,int v,intw,int rw=0){
    e[cnt]=(edge){v,head[u],w,0};
    head[u]=cnt++;
    e[cnt]=(edge){u,head[v],rw,0};
    head[v]=cnt++;
}
intq[N];
voidbfs(int st,int ed){
    memset(dep,-1,sizeofdep);
    memset(gap,0,sizeofgap);
    gap[0]=1;
    intfront=0,rear=0;
    dep[ed]=0;
    q[rear++]=ed;
    while(front!=rear){
        intu=q[front++];
        for(inti=head[u];~i;i=e[i].next){
            intv=e[i].to;
            if(dep[v]!=-1)continue;
            q[rear++]=v;
            dep[v]=dep[u]+1;
            gap[dep[v]]++;
        }
    }
}
ints[N];
intsap(int st,int ed,intn){
    bfs(st,ed);
    memcpy(cur,head,sizeofhead);
    inttop=0;
    intu=st;
    intans=0;
    while(dep[st]<n){
        if(u==ed){
            intMin=inf;
            intinser;
            for(inti=0;i<top;i++)
                if(Min>e[s[i]].cap-e[s[i]].flow){
                    Min=e[s[i]].cap-e[s[i]].flow;
                    inser=i;
                }
            for(inti=0;i<top;i++){
                e[s[i]].flow+=Min;
                e[s[i]^1].flow-=Min;
            }
            ans+=Min;
            top=inser;
            u=e[s[top]^1].to;
            continue;
        }
        boolflag=false;
        intv;
        for(inti=cur[u];~i;i=e[i].next){
            v=e[i].to;
            if(e[i].cap-e[i].flow&&dep[v]+1==dep[u]){
                flag=true;
                cur[u]=i;
                break;
            }
        }
        if(flag){
            s[top++]=cur[u];
            u=v;
            continue;
        }
        intMin=n;
        for(inti=head[u];~i;i=e[i].next)
            if(e[i].cap-e[i].flow &&dep[e[i].to]<Min){
                Min=dep[e[i].to];
                cur[u]=i;
            }
        gap[dep[u]]--;
        if(!gap[dep[u]])returnans;
        gap[dep[u]=Min+1]++;
        if(u!=st)u=e[s[--top]^1].to;
    }
    returnans;
}
intn,m;
intg[N][N],vis[N],d[N];
voidsolve(){
    intl=0,r=0;
    q[0]=1;
    d[1]=0;
    memset(vis,0,sizeofvis);
    while(l<=r){
        intk=q[l++];
        for(inti=2;i<=n;i++)if(g[k][i]!=-1){
            if(vis[i])continue;
            q[++r]=i;
            vis[i]=1;
            d[i]=d[k]+1;
        }
    }
    init();
    for(inti=1;i<=n;i++)
    for(intj=1;j<=n;j++)
    if(g[i][j]!=-1&&d[j]==d[i]+1)
        add(i,j,g[i][j]);
     
    printf("%d\n",sap(1,n,n));
}
intmain() {
    intt;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        memset(g,-1,sizeofg);
        for(inti=1;i<=m;i++){
            intu,v,w;
            scanf("%d%d%d",&u,&v,&w);
            g[v][u]=g[u][v]=w;
        }
        solve();
    }
    return0;
}
0 0
原创粉丝点击