• 2014ACM/ICPC亚洲区鞍山站 清华命题


    http://acm.hdu.edu.cn/showproblem.php?pid=5070

    先跳过。

    http://acm.hdu.edu.cn/showproblem.php?pid=5071

    维护一个聊天队列,有8种操作,每次操作完要打印对应的信息,认真读题,按题意模拟,一维数组模拟队列就可以,5000操作,交换删除等on暴力复杂度也不会超时。

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<map>
      4 using namespace std;
      5 const int M=32;
      6 char a[M];
      7 char b[M][M]={"","Add","Close","Chat","Rotate","Prior","Choose","Top","Untop"};
      8 map<int,int> mp;
      9 int sta[5010],top,cnt,x;
     10 void success(){
     11     puts("success.");
     12 }
     13 void invalid(){
     14     puts("invalid priority.");
     15 }
     16 void Empty(){
     17     puts("empty.");
     18 }
     19 void solve1(){
     20     for(int i=0;i<cnt;i++){
     21         if(sta[i]==x){
     22             puts("same priority.");
     23             return ;
     24         }
     25     }
     26     sta[cnt++]=x;
     27     success();
     28 }
     29 void solve2(){
     30     for(int i=0;i<cnt;i++){
     31         if(sta[i]==x){
     32             if(top==x) top=-1;
     33             for(int j=i;j<cnt-1;j++){
     34                 sta[j]=sta[j+1];
     35             }
     36             cnt--;
     37             printf("close %d with %d.
    ",x,mp[x]);
     38             mp.erase(x);
     39             return ;
     40         }
     41     }
     42     invalid();
     43 }
     44 void solve3(){
     45     if(!cnt){
     46         Empty();
     47         return ;
     48     }
     49     if(top!=-1){
     50         mp[top]+=x;
     51         success();
     52         return ;
     53     }
     54     mp[sta[0]]+=x;
     55     success();
     56 }
     57 void solve4(int id){
     58     if(id<1||id>cnt){
     59         puts("out of range.");
     60         return ;
     61     }
     62     int tmp=sta[id-1];
     63     for(int i=id-1;i>0;i--){
     64         sta[i]=sta[i-1];
     65     }
     66     sta[0]=tmp;
     67     success();
     68 }
     69 void solve5(){
     70     if(!cnt){
     71         Empty();
     72         return ;
     73     }
     74     int id=0;
     75     for(int i=0;i<cnt;i++){
     76         if(sta[i]>sta[id]){
     77             id=i;
     78         }
     79     }
     80     solve4(id+1);
     81 }
     82 void solve6(){
     83     for(int i=0;i<cnt;i++){
     84         if(sta[i]==x){
     85             solve4(i+1);
     86             return ;
     87         }
     88     }
     89     invalid();
     90 }
     91 void solve7(){
     92     for(int i=0;i<cnt;i++){
     93         if(sta[i]==x){
     94             top=x;
     95             success();
     96             return ;
     97         }
     98     }
     99     invalid();
    100 }
    101 void solve8(){
    102     if(top!=-1){
    103         top=-1;
    104         success();
    105         return ;
    106     }
    107     puts("no such person.");
    108 }
    109 int main(){
    110     int t,n;
    111     while(~scanf("%d",&t)){
    112         while(t--){
    113             scanf("%d",&n);
    114             int cas=1;
    115             top=-1,cnt=0;
    116             mp.clear();
    117             while(n--){
    118                 scanf("%s",a);
    119                 int id=1;
    120                 for(int i=1;i<=8;i++){
    121                     if(!strcmp(a,b[i])){
    122                         id=i;
    123                         break;
    124                     }
    125                 }
    126                 if(id!=5&&id!=8){
    127                     scanf("%d",&x);
    128                 }
    129                 printf("Operation #%d: ",cas++);
    130                 if(id==1){
    131                     solve1();
    132                 }
    133                 else if(id==2){
    134                     solve2();
    135                 }
    136                 else if(id==3){
    137                     solve3();
    138                 }
    139                 else if(id==4){
    140                     solve4(x);
    141                 }
    142                 else if(id==5){
    143                     solve5();
    144                 }
    145                 else if(id==6){
    146                     solve6();
    147                 }
    148                 else if(id==7){
    149                     solve7();
    150                 }
    151                 else{
    152                     solve8();
    153                 }
    154             }
    155             if(top!=-1&&mp[top]){
    156                 printf("Bye %d: %d
    ",top,mp[top]);
    157             }
    158             for(int i=0;i<cnt;i++){
    159                 if(top!=sta[i]&&mp[sta[i]]){
    160                     printf("Bye %d: %d
    ",sta[i],mp[sta[i]]);
    161                 }
    162             }
    163         }
    164     }
    165     return 0;
    166 }
    View Code

    http://acm.hdu.edu.cn/showproblem.php?pid=5072

    输入n个数,n<=10^5,其中选出3个数,满足两两之间互质,或者两两之间都不互质,问有多少种不同的选法。

    解法:暴力n^3,然后加3次gcd判断,统计。明显超时,但可以用来测测。

    根据 模型请参考 《算法竞赛入门经典 训练指南》  p105 问题6,大白书。

    那个模型是这样的,给定空间n个点n==1000,没有3点共线,每两个点之间都用红色或黑色边连接,求3条边同色的三角形个数。

    那么对于这个题,我们可以把每个数当做三角形的点,数与数之间互质当做红边,不互质当做黑边,那么就是这个问题了。

    三角形这个题,可以求反面,求出非单色三角形,就可以用总数扣去得到答案。对于非单色三角形,必然有两个点连的两条边不同色。

    所以对每个点,如果有ai条红色边,就有n-1-ai条蓝色边,ai*(n-1-ai)就是该点形成的非单色三角形,因为一个三角形会算两次,(必然有两个点连的两条边不同色)。所以除二。

    对于上面这个题,一样的方法,对每个数,求出有多少个互质的,假设求出来是bi,那么不互质的就是(n-1-bi),那么这个数能贡献的答案就是bi*(n-1-bi),因为每种情况会重复算一次,所以最后答案除2就是不合法的情况,用总数减去就是题目所求。

    问题只剩下如何求bi,多少个互质的,然后就是二进制暴力质因子,容斥原理++--,理解一下。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define mt(a,b) memset(a,b,sizeof(a))
     5 using namespace std;
     6 typedef long long LL;
     7 const int M=1e5+10;
     8 int pri[M],mark[M],pricnt;//mark[i]存i的最小因子,素数时mark[i]==i
     9 void sieve_primes() { //筛素数
    10     pricnt=0;
    11     mt(mark,0);
    12     mark[0]=mark[1]=1;
    13     for(int i=2; i<M; i++) {
    14         if(!mark[i]) pri[pricnt++]=mark[i]=i;
    15         for(int j=0; pri[j]*i<M; j++) {
    16             mark[i*pri[j]]=pri[j];
    17             if(!(i%pri[j])) break;
    18         }
    19     }
    20 }
    21 int fac[128];
    22 int find_fac_before_sieve(int n) { //筛完素数后用,n<M
    23     int cnt=0;
    24     while(mark[n]!=1) {
    25         fac[cnt++]=mark[n];
    26         n/=mark[n];
    27     }
    28     return cnt;
    29 }
    30 int num[M];
    31 int lf;
    32 void dfs(int now,int sum){
    33     if(now==lf){
    34         num[sum]++;
    35         return ;
    36     }
    37     dfs(now+1,sum);
    38     dfs(now+1,sum*fac[now]);
    39 }
    40 LL help;
    41 void dfs_ans(int now,int sum,int cnt){
    42     if(now==lf){
    43 //        if(!cnt) return ;
    44         if(cnt&1) help-=num[sum];
    45         else      help+=num[sum];
    46         return ;
    47     }
    48     dfs_ans(now+1,sum,cnt);
    49     dfs_ans(now+1,sum*fac[now],cnt+1);
    50 }
    51 int a[M];
    52 int main(){
    53     sieve_primes();
    54     int t,n;
    55     while(~scanf("%d",&t)){
    56         while(t--){
    57             scanf("%d",&n);
    58             for(int i=0;i<n;i++){
    59                 scanf("%d",&a[i]);
    60             }
    61             mt(num,0);
    62             for(int i=0;i<n;i++){
    63                 lf=find_fac_before_sieve(a[i]);
    64                 lf=unique(fac,fac+lf)-fac;
    65                 dfs(0,1);
    66             }
    67             LL ans=0;
    68             for(int i=0;i<n;i++){
    69                 lf=find_fac_before_sieve(a[i]);
    70                 lf=unique(fac,fac+lf)-fac;
    71                 help=0;
    72                 dfs_ans(0,1,0);
    73                 if(a[i]==1) help--;
    74                 ans+=help*(n-1-help);
    75             }
    76             printf("%lld
    ",1LL*n*(n-1)*(n-2)/6-ans/2);
    77         }
    78     }
    79     return 0;
    80 }
    View Code

    D http://acm.hdu.edu.cn/showproblem.php?pid=5073

    输入一维数轴上n个坐标,每个点重量是1,可以允许最多移动k个点,允许移动到同一个位置,问如何移动使得(每个点到重心的距离的平方)的和最小。

     因为重量都是1,所以重心就会落在n个坐标的平均值位置。

    一个先决条件是,k个点一定都要移动,那么剩下n-k个点去求那个权值。

    因为移动的k个点可以都移动到剩下点的重心去,那么他们对权值的贡献就是零,相当于直接删去。

    还有一个条件是,为了使得大家距离重心更近,那么肯定留下的n-k个点要连续,这样肯定比离散的距离重心近。

    所以我们将坐标排序,枚举起点,求长度为n-k这一段的权值,最后取最小值。

    问题就需要尽快的求出一个连续段的权值。

    对于距离平方求和,就是(Xi-Xavg)^2=Xi^2-2*Xi*Xavg+Xavg^2     (L<=i<=R)

    求均值预处理前n项和即可,第一项就预处理前n项平方和。

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 const int M=5e4+10;
     5 int a[M];
     6 int main(){
     7     int t,n,m;
     8     while(~scanf("%d",&t)){
     9         while(t--){
    10             scanf("%d%d",&n,&m);
    11             for(int i=0;i<n;i++){
    12                 scanf("%d",&a[i]);
    13             }
    14             if(n==m){
    15                 puts("0");
    16                 continue;
    17             }
    18             sort(a,a+n);
    19             double sum=0,sum2=0;
    20             int cnt=n-m;
    21             for(int i=0;i<cnt;i++){
    22                 sum+=a[i];
    23                 sum2+=1.0*a[i]*a[i];
    24             }
    25             double ans=sum2-2*(sum/cnt)*sum+sum/cnt*sum;
    26             for(int i=cnt;i<n;i++){
    27                 sum+=a[i];
    28                 sum-=a[i-cnt];
    29                 sum2+=1.0*a[i]*a[i];
    30                 sum2-=1.0*a[i-cnt]*a[i-cnt];
    31                 double now=sum2-2*(sum/cnt)*sum+sum/cnt*sum;
    32                 ans=min(ans,now);
    33             }
    34             printf("%.10f
    ",ans);
    35         }
    36     }
    37     return 0;
    38 }
    View Code

    E http://acm.hdu.edu.cn/showproblem.php?pid=5074

    输入n个数的序列,序列的得分是ai和ai+1之间贡献的,也就是有n-1个得分。数字一定是1到m的,输入会给出m*m的矩阵,即矩阵mat【i】【j】 表示 i 在 j 前面的得分。序列中值为1到m的是必须选择该值,值为-1的是你可以在1到m中任意选一个放在该位置,最后要求序列可能得到的最大分数。

    解法:若枚举,如果n个都是-1,每一个有1到m种情况,总情况数就是m的n次方,50^100,观察发现,有最优子结构性质,即dp【n】【m】表示前n个以m为结尾所能得到的最大分数。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define mt(a,b) memset(a,b,sizeof(a))
     5 using namespace std;
     6 const int M=64;
     7 int dp[M<<1][M],a[M][M],b[M<<1];
     8 int main(){
     9     int t,n,m;
    10     while(~scanf("%d",&t)){
    11         while(t--){
    12             scanf("%d%d",&n,&m);
    13             for(int i=1;i<=m;i++){
    14                 for(int j=1;j<=m;j++){
    15                     scanf("%d",&a[i][j]);
    16                 }
    17             }
    18             for(int i=1;i<=n;i++){
    19                 scanf("%d",&b[i]);
    20             }
    21             mt(dp,-1);
    22             if(b[1]==-1){
    23                 for(int j=1;j<=m;j++){
    24                     dp[1][j]=0;
    25                 }
    26             }
    27             else{
    28                 dp[1][b[1]]=0;
    29             }
    30             for(int i=1;i<n;i++){
    31                 for(int j=1;j<=m;j++){
    32                     if(dp[i][j]==-1) continue;
    33                     if(b[i+1]>0){
    34                         dp[i+1][b[i+1]]=max(dp[i+1][b[i+1]],dp[i][j]+a[j][b[i+1]]);
    35                         continue;
    36                     }
    37                     for(int k=1;k<=m;k++){
    38                         dp[i+1][k]=max(dp[i+1][k],dp[i][j]+a[j][k]);
    39                     }
    40                 }
    41             }
    42             int ans=0;
    43             for(int j=1;j<=m;j++){
    44                 ans=max(ans,dp[n][j]);
    45             }
    46             printf("%d
    ",ans);
    47         }
    48     }
    49     return 0;
    50 }
    View Code

    I   http://acm.hdu.edu.cn/showproblem.php?pid=5078

    输入n个点,每个点有时间t,坐标x,y。定义相邻两点之间的难度为距离/时间差,求最大的难度。

    解法:按照定义算相邻两个的难度,取最大值。

     1 #include<cstdio>
     2 #include<cmath>
     3 #include<algorithm>
     4 using namespace std;
     5 const int M=1e3+10;
     6 struct G{
     7     double t,x,y;
     8 }g[M];
     9 double f(G a,G b){
    10     return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y))/(b.t-a.t);
    11 }
    12 int main(){
    13     int t,n;
    14     while(~scanf("%d",&t)){
    15         while(t--){
    16             scanf("%d",&n);
    17             for(int i=0;i<n;i++){
    18                 scanf("%lf%lf%lf",&g[i].t,&g[i].x,&g[i].y);
    19             }
    20             double ans=f(g[0],g[1]);
    21             for(int i=2;i<n;i++){
    22                 ans=max(ans,f(g[i-1],g[i]));
    23             }
    24             printf("%.10f
    ",ans);
    25         }
    26     }
    27     return 0;
    28 }
    View Code
  • 相关阅读:
    移植nand驱动补缺:make mrproper与make clean以及make distclean,find/grep. makefile
    repo使用
    git使用总结
    notepade++使用
    linux内核源代码、配置与编译
    linux内核介绍
    块设备
    PHP和javascript中url编码解码详解
    python中的类方法、静态方法、对象方法
    webpack+vue中安装使用vue-layer弹窗插件
  • 原文地址:https://www.cnblogs.com/gaolzzxin/p/4658724.html
Copyright © 2020-2023  润新知