前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【2016 ACM/ICPC Asia Regional Qingdao Online】

【2016 ACM/ICPC Asia Regional Qingdao Online】

作者头像
饶文津
发布2020-06-02 15:58:05
7410
发布2020-06-02 15:58:05
举报
文章被收录于专栏:饶文津的专栏饶文津的专栏

[ HDU 5878 ] I Count Two Three

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

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

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

[ HDU 5879 ] Cure

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

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

[ HDU 5881 ] Tea

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

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

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

[ HDU 5884 ] Sort

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

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

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

[ HDU 5887 ]  Herbs Gathering

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

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

[ HDU 5889 ] Barricade

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

/*
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
using namespace std;
struct edge{
    int to,next,cap,flow;
}e[M];
int head[N],cnt;
int gap[N],dep[N],cur[N];
void init(){
    cnt=0;
    memset(head, -1, sizeof head);
}
void add(int u,int v,int w,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++;
}
int q[N];
void bfs(int st,int ed){
    memset(dep,-1,sizeof dep);
    memset(gap,0,sizeof gap);
    gap[0]=1;
    int front=0,rear=0;
    dep[ed]=0;
    q[rear++]=ed;
    while(front!=rear){
        int u=q[front++];
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            if(dep[v]!=-1)continue;
            q[rear++]=v;
            dep[v]=dep[u]+1;
            gap[dep[v]]++;
        }
    }
}
int s[N];
int sap(int st,int ed,int n){
    bfs(st,ed);
    memcpy(cur,head,sizeof head);
    int top=0;
    int u=st;
    int ans=0;
    while(dep[st]<n){
        if(u==ed){
            int Min=inf;
            int inser;
            for(int i=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(int i=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;
        }
        bool flag=false;
        int v;
        for(int i=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;
        }
        int Min=n;
        for(int i=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]])return ans;
        gap[dep[u]=Min+1]++;
        if(u!=st)u=e[s[--top]^1].to;
    }
    return ans;
}
int n,m;
int g[N][N],vis[N],d[N];
void solve(){
    int l=0,r=0;
    q[0]=1;
    d[1]=0;
    memset(vis,0,sizeof vis);
    while(l<=r){
        int k=q[l++];
        for(int i=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(int i=1;i<=n;i++)
    for(int j=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));
}
int main() {
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        memset(g,-1,sizeof g);
        for(int i=1;i<=m;i++){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            g[v][u]=g[u][v]=w;
        }
        solve();
    }
    return 0;
}

小结:这次比赛既没带草稿纸又没带笔,还迟到,我们的态度太不认真了,不过睡得那么晚我真是起不来啊。我觉得我们还要多练多做,我发现很多基本的知识都不熟悉。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-09-18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • [ HDU 5878 ] I Count Two Three
  • [ HDU 5879 ] Cure
  • [ HDU 5881 ] Tea
  • [ HDU 5882 ] Balanced Game
  • [ HDU 5883 ] The Best Path
  • [ HDU 5884 ] Sort
  • [ HDU 5887 ]  Herbs Gathering
  • [ HDU 5889 ] Barricade
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档