zoukankan      html  css  js  c++  java
  • 【2016 ACM/ICPC Asia Regional Qingdao Online】

    [ 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
    ",ans[lower_bound(ans,ans+cnt,n)-ans]);
    39     }
    40 }
    View Code

    [ 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
    ",get());
    30         memset(n,0,sizeof n);
    31     }
    32 }
    View Code

    [ 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
    ",ans);
    28     }
    29     return 0;
    30 }
    View Code

    [ 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
    ",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 }
    View Code

    [ 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
    ",l);
    56     }
    57     return 0;
    58 }
    View Code

    [ 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]
    ",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
    ",ans);
    58     }
    59     
    60 }
    View Code

    [ 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
    ",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;
    }

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

  • 相关阅读:
    删除无效的SQL SERVER组中的注册的几种方法
    SQLServer中把某个表里的记录复制到另一个数据库的表中
    文件上传 带进度条(多种风格)
    Team Leader你会带团队吗?你懂合作吗?你好像都不会啊!(上)
    整理.Net代码生成器(转)
    SQL SERVER 2000数据库,转换为ACCESS数据库(已解决ACCESS自动编号问题)
    js中prototype用法
    js在火狐和IE浏览器的差异
    Varnish介绍
    C# 4.0 新特性
  • 原文地址:https://www.cnblogs.com/flipped/p/5880187.html
Copyright © 2011-2022 走看看