zoukankan      html  css  js  c++  java
  • 2017-10-02-morning

    T1 一道图论神题(god)

    Time Limit:1000ms   Memory Limit:128MB

    题目描述

    LYK有一张无向图G={V,E},这张无向图有n个点m条边组成。并且这是一张带权图,只有点权。

    LYK想把这个图删干净,它的方法是这样的。每次选择一个点,将它删掉,但删这个点是需要代价的。假设与这个点相连的还没被删掉的点是u1,u2,…,uk。LYK将会增加a[u1],a[u2],…,a[uk]的疲劳值。

    它想将所有点都删掉,并且删完后自己的疲劳值之和最小。你能帮帮它吗?

    输入格式(god.in)

        第一行两个数n,m表示一张n个点m条边的图。

        第二行n个数ai表示点权。

        接下来m行每行三个数u,v,表示有一条连接u,v的边。数据保证任意两个点之间最多一条边相连,并且不存在自环。

    输出格式(god.out)

    你需要输出这个最小疲劳值是多少。

    输入样例

    4 3

    10 20 30 40

    1 4

    1 2

    2 3

    输出样例

    40

    样例解释

    一个合理的方法是先删4号点,此时有10点疲劳值。接下来删3号点,获得20点疲劳值,再删2号点,获得10点疲劳值,最后删1号点,没有疲劳值。总计40点疲劳值。

    对于30%的数据n<=10。

    对于60%的数据n,m<=1000。

    对于100%的数据1<=n,m,ai<=100000

     1 /*
     2 对于一条边的两个端点,肯定是选权值大最优 
     3 然后对于每条边,都采取这种策略就完成了 
     4 */
     5 #include <algorithm>
     6 #include <cstdio>
     7 
     8 inline void read(int &x)
     9 {
    10     x=0; register char ch=getchar();
    11     for(; ch>'9'||ch<'0'; ) ch=getchar();
    12     for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0';
    13 }
    14 const int N(100005);
    15 int n,m,val[N];
    16 long long ans;
    17 
    18 int Presist()
    19 {
    20     freopen("god.in","r",stdin);
    21     freopen("god.out","w",stdout);
    22     read(n),read(m);
    23     for(int i=1; i<=n; ++i)    read(val[i]);
    24     for(int u,v,i=1; i<=m; ++i)
    25     {
    26         read(u),read(v);
    27         ans+=(long long)std::min(val[u],val[v]);
    28     }
    29     printf("%I64d",ans);
    30     return 0;
    31 }
    32 
    33 int Aptal=Presist();
    34 int main(int argc,char**){;}
    贪心AC

     

    T2 位运算2(bit)

    Time Limit:1000ms   Memory Limit:128MB

    题目描述

    LYK拥有一个十进制的数N。它赋予了N一个新的意义:不考虑N的符号,将N每一位都拆开来后再加起来就是N所拥有的价值。例如数字123拥有6的价值,数字999拥有27的价值,数字-233拥有8的价值。

    假设数字N的价值是K,LYK想找到一个价值是K+1的数字,当然这个答案实在太多了,LYK想使得这个价值为K+1的数字尽可能大,并且需要保证这个数字小于N。

    输入格式(bit.in)

        一个整数N。

    输出格式(bit.out)

    一个数表示答案。你需要输出一个整数,且这个数不包含前导0。

    输入样例1

    199

    输出样例1

    -299

    输入样例2

    1520

    输出样例2

    1512

    对于20%的数据|N|<=10

    对于40%的数据|N|<=100

    对于60%的数据|N|<=10^9

    对于80%的数据|N|<=10^1000

    对于100%的数据|N|<=10^100000。

    对于负数的情况从后往前找第一个不是9的数++

     1 #include <cstring>
     2 #include <cstdio>
     3 
     4 inline void read(int &x)
     5 {
     6     x=0; register char ch=getchar();
     7     for(; ch>'9'||ch<'0'; ) ch=getchar();
     8     for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0';
     9 }
    10 char s[100005];
    11 int n,num[100005];
    12 
    13 inline void work1()
    14 {
    15     int i,flag=0;
    16     for(i=2; i<=n; ++i) num[i]=s[i]-'0';
    17     for(i=n; i>1; --i)
    18         if(num[i]!=9)
    19         {
    20             num[i]++;
    21             flag=1;
    22             break;
    23         }
    24     printf("-");
    25     if(!flag) printf("1");
    26     for(int i=2; i<=n; ++i)    printf("%d",num[i]);
    27 }
    28 
    29 int K;
    30 inline void work2()
    31 {
    32     for(int i=1; i<=n; ++i) num[i]=s[i]-'0',K+=num[i];
    33     if(num[1]==1&&num[2]==0&&n==2) { printf("%d
    ",2); return ; }
    34     if(++K<10&&n==2&&num[1]==1) { printf("%d
    ",K); return ; }
    35 }
    36 
    37 int Presist()
    38 {
    39 //    freopen("bit.in","r",stdin);
    40 //    freopen("bit.out","w",stdout);
    41     scanf("%s",s+1);n=strlen(s+1);
    42     if(s[1]=='-') work1();
    43     else work2();
    44     return 0;
    45 }
    46 
    47 int Aptal=Presist();
    48 int main(int argc,char**){;}
    考试只做了负数和特殊正数的情况60分

     对于正数的情况,

    ①设当前位置i到最后一位的价值为tot,如果tot<=(n-i)*9+num[i]-1

    最优解为1~i-1为原数,i+1~n尽量填最大,num[i]--;

    ②否则,为绝对数值最小的负数,等价于位数最小的负数,第一位之后填尽量多的9

     1 #include <cstring>
     2 #include <cstdio>
     3 
     4 inline void read(int &x)
     5 {
     6     x=0; register char ch=getchar();
     7     for(; ch>'9'||ch<'0'; ) ch=getchar();
     8     for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0';
     9 }
    10 const int N(100005);
    11 int n,num[N],k[N],K;
    12 char s[N];
    13 
    14 inline void work1()
    15 {
    16     int i,flag=0;
    17     for(i=2; i<=n; ++i) num[i]=s[i]-'0';
    18     for(i=n; i>1; --i)
    19         if(num[i]!=9)
    20         {
    21             num[i]++;
    22             flag=1;
    23             break;
    24         }
    25     printf("-");
    26     if(!flag) printf("1");
    27     for(int i=2; i<=n; ++i)    printf("%d",num[i]);
    28 }
    29 
    30 inline void work2()
    31 {
    32     for(int i=1; i<=n; ++i) num[i]=s[i]-'0',K+=num[i];
    33     int tot=num[n]+1;
    34     for(int i=n-1; i>=1; --i)
    35     {
    36         tot+=num[i];
    37         if(!num[i]) continue;
    38         if(tot<=num[i]-1+(n-i)*9)
    39         {
    40             num[i]--;tot-=num[i];
    41             if(num[1]) printf("%d",num[1]);
    42             for(int j=2; j<=i; ++j) printf("%d",num[j]);
    43             for(int j=i+1; j<=n; ++j)
    44                 if(tot>=9) printf("9"),tot-=9;
    45                 else printf("%d",tot),tot=0;
    46             return ;
    47         }
    48     }
    49     printf("-"); K++; int len=K/9;
    50     if(K%9) printf("%d",K%9);
    51     for(; len--; ) printf("9");
    52 }
    53 
    54 int Presist()
    55 {
    56 //    freopen("bit.in","r",stdin);
    57 //    freopen("bit.out","w",stdout);
    58     scanf("%s",s+1);n=strlen(s+1);
    59     if(s[1]=='-') work1();
    60     else work2();
    61     return 0;
    62 }
    63 
    64 int Aptal=Presist();
    65 int main(int argc,char**){;}
    AC

    T3 逆序对(pair)

    Time Limit:1000ms   Memory Limit:128MB

    题目描述

    LYK最近在研究逆序对。

    这个问题是这样的。

    一开始LYK有一个2^n长度的数组ai。

    LYK有Q次操作,每次操作都有一个参数k。表示每连续2^k长度作为一个小组。假设n=4,k=2,则a[1],a[2],a[3],a[4]为一个小组,a[5],a[6],a[7],a[8]为一个小组,a[9],a[10],a[11],a[12]为一个小组,a[13],a[14],a[15],a[16]也为一个小组。

    然后LYK对于每个小组都翻转,也就是说原数组会变成a[4],a[3],a[2],a[1],a[8],a[7],a[6],a[5],a[12],a[11],a[10],a[9],a[16],a[15],a[14],a[13]。之后它想求出这2^n个数的逆序对是多少。

    因此你需要输出对于每次操作,操作完后这2^n个数的逆序对有多少对。

    两个数ai,aj被称为逆序对当且仅当i<j且ai>aj。

    输入格式(pair.in)

        第一行一个数n。

    接下来一行2^n个数ai表示一开始的数组。

    接下来一行一个数Q,表示操作的次数。

    接下来一行Q个数,表示每次操作的参数k。

    输出格式(pair.out)

    Q行,表示每次操作后的答案。

    输入样例

    2

    2 1 4 3

    4

    1 2 0 2

    输出样例

    0

    6

    6

    0

    样例解释

    第一次操作,{2,1,4,3}->{1,2,3,4}

    第二次操作,{1,2,3,4}->{4,3,2,1}

    第三次操作,{4,3,2,1}->{4,3,2,1}       

    第四次操作,{4,3,2,1}->{1,2,3,4}

    对于30%的数据n<=10,Q<=10。

    对于50%的数据n<=10,Q<=1000。

    对于80%的数据n<=10,Q<=200000。

    对于100%的数据n<=17,Q<=200000,1<=ai<=2^n。

    归并排序求逆序对的时候,用st表维护从第i个位置,长为2^j的区间的逆序对个数

    然后求出对应区间的顺序对个数

    维护所有长为2^i的区间的逆序对个数rev[i]和顺序对个数seq[i]

    统计答案的时候,拆分就是swap(rev,seq)

    在这里顺序对个数是用总个数-逆序对个数求的,要注意相等的情况

    因为用总个数-逆序对个数=顺序对个数+相等的数对

    所以归并过程中,还要预处理从第i个位置,长为2^j的区间的相等数对个数

    计算rev,seq时,同时计算same[i],表示所有长为2^i的区间相等的数对个数

    求解的时候 先swap(rev,seq),然后rev-=same,再seq=总的-rev

     1 #include <cstdio>
     2 
     3 #define LL long long
     4 #define swap(a,b) {LL c=a;a=b;b=c;}
     5 
     6 inline void read(int &x)
     7 {
     8     x=0; register char ch=getchar();
     9     for(; ch>'9'||ch<'0'; ) ch=getchar();
    10     for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0';
    11 }
    12 const int N(1<<17);
    13 int n,nn,m,a[N+5],log2[N+5];
    14 
    15 int last[N+5],order[N+5];
    16 LL st[N+5][18],euq[N+5][18];
    17 LL same[N+5],seq[N+5],rev[N+5],sum[N+5];
    18 void Merge_sort(int l,int r)
    19 {
    20     if(l==r) return ;
    21     int mid=l+r>>1;
    22     Merge_sort(l,mid);
    23     Merge_sort(mid+1,r);
    24     int i,j,k,len=log2[r-l+1];
    25     for(i=l; i<=r; ++i) last[i]=i;
    26     for(i=r; i>l; --i)
    27         if(a[i]==a[i-1]) last[i-1]=last[i];
    28     for(i=k=l,j=mid+1; i<=mid&&j<=r; )
    29         if(a[i]==a[j]) euq[l][len]+=last[j]-j+1,order[k++]=a[i++];
    30         else if(a[i]>a[j]) st[l][len]+=mid-i+1,order[k++]=a[j++];
    31              else order[k++]=a[i++];
    32     for(; i<=mid; ) order[k++]=a[i++];
    33     for(; j<=r; ) order[k++]=a[j++];
    34     for(i=l; i<=r; ++i) a[i]=order[i];
    35 }
    36 
    37 inline void Prepare()
    38 {
    39     for(int i=2; i<=nn; ++i) log2[i]=log2[i>>1]+1;
    40     Merge_sort(1,nn);
    41     for(int i=1; i<=n; ++i) sum[i]=1ll*(1<<i-1)*(1<<i-1);
    42     for(int len=2,i=1; i<=n; ++i,len<<=1)
    43       for(int j=1; j<=nn; j+=len)
    44       {
    45         rev[i]+=st[j][i],
    46         same[i]+=euq[j][i],
    47         seq[i]+=sum[i]-st[j][i];
    48       }
    49 }
    50 
    51 int Presist()
    52 {
    53 //    freopen("pair.in","r",stdin);
    54 //    freopen("pair.out","w",stdout);
    55     read(n),nn=1<<n;
    56     for(int i=1; i<=nn; ++i) read(a[i]);
    57     Prepare(),read(m);
    58     for(int k; m--; )
    59     {
    60         read(k);long long ans=0;
    61         for(int i=1; i<=k; ++i)
    62         {
    63             swap(rev[i],seq[i]);
    64             rev[i]-=same[i];
    65             seq[i]=sum[i]*nn/(1<<i)-rev[i];
    66         }
    67         for(int i=1; i<=n; ++i) ans+=rev[i];
    68         printf("%I64d
    ",ans);
    69     }
    70     return 0;
    71 }
    72 
    73 int Aptal=Presist();
    74 int main(int argc,char**argv){;}
    AC
    ——每当你想要放弃的时候,就想想是为了什么才一路坚持到现在。
  • 相关阅读:
    0909初识操作系统
    实验四主存空间的分配和回收
    实验一 DOS命令解释程序的编写
    0909关于操作系统
    实验四主存空间的分配和回收
    实验3评价
    实验一 DOS命令解释程序的编写
    实验三、进程调度模拟程序实验
    实验二、作业调度实验
    0909 第一次上机课之《为什么学操作系统?》
  • 原文地址:https://www.cnblogs.com/Shy-key/p/7652451.html
Copyright © 2011-2022 走看看