zoukankan      html  css  js  c++  java
  • 20171015 杂题

    BZOJ[4563] [Haoi2016]放棋子

    这个题是由套路的,可以直接用错排公式,首先f[1]=0,f[2]=1,然后考虑后面的转移,当放第i个的时候,前面的只可能是i-1个全部都不在自己的位置或者只有1个不在自己的位置,对于前者,第i个可以和前i-1个中的任意一个互换位置,贡献就是f[i-1]*(i-1),对于后者,第i个只能和在自己位置上的互换位置,贡献就是f[i-2]*(i-1);,然后套一个高精就行了

     1 #include <cmath>
     2 #include <cstdio>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <iostream>
     6 #include <algorithm>
     7 using namespace std;
     8 int n;
     9 void init(){int x;for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&x);}
    10 struct Bignum{
    11     int num[6000],len;
    12     Bignum(){memset(num,0,sizeof(num)); len=0;}
    13     void clear(){memset(num,0,sizeof(num)); len=0;}
    14     void pt(){
    15         for(int i=len;i>=1;i--){
    16             printf("%d",num[i]);
    17         } printf("
    ");
    18     }
    19 };
    20 Bignum c;
    21 Bignum operator * (const Bignum a,const int b){
    22     c.clear(); int len=a.len;
    23     for(int i=1;i<=len;i++){
    24         c.num[i]+=a.num[i]*b;
    25         c.num[i+1]+=c.num[i]/10;
    26         c.num[i]%=10;
    27     }
    28     if(c.num[len+1]) len++;
    29     while(c.num[len]>10){
    30         c.num[len+1]+=c.num[len]/10;
    31         c.num[len]%=10;
    32         len++;
    33     }
    34     c.len=len; return c;
    35 }
    36 Bignum operator + (const Bignum a,const Bignum b){
    37     c.clear(); int len=a.len+b.len;
    38     for(int i=1;i<=len;i++){
    39         c.num[i]+=a.num[i]+b.num[i];
    40         c.num[i+1]+=c.num[i]/10;
    41         c.num[i]%=10;
    42     }
    43     if(c.num[len+1]) len++;
    44     while(!c.num[len]) len--;
    45     c.len=len; return c;
    46 }
    47 Bignum f[2010];
    48 void work(){
    49     f[1].num[1]=0; f[1].len=1; f[2].num[1]=1;  f[2].len=1;
    50     for(int i=3;i<=n;i++){
    51         f[i]=(f[i-1]+f[i-2])*(i-1);
    52     }
    53     f[n].pt();
    54 }
    55 void tst(){
    56     Bignum a,b;
    57     a.len=1; a.num[1]=1;
    58     a=a*1234; a.pt();
    59     b=a; b=b+a; 
    60     b.pt();
    61 }
    62 int main(){
    63     scanf("%d",&n);
    64     init();
    65     work();
    66     return 0;
    67 }
    View Code

    BZOJ[3170] [Tjoi 2013]松鼠聚会

    可以神奇的把这个切比雪夫距离转化为曼哈顿距离(之前学长好想提到过一次),具体的证明还是挺简单的 http://blog.csdn.net/slongle_amazing/article/details/50911504

     1 #include <cmath>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cstdlib>
     5 #include <iostream>
     6 #include <algorithm>
     7 # define maxn 100010
     8 using namespace std;
     9 typedef long long LL;
    10 int n;
    11 struct node {
    12     LL x,y,sumx,sumy;
    13     node(){sumx=0; sumy=0;}
    14 }g[maxn];
    15 void init(){
    16     scanf("%d",&n);
    17     int x,y;
    18     for(int i=1;i<=n;i++){
    19         scanf("%d%d",&x,&y);
    20         g[i].x=x+y; g[i].y=x-y;
    21 //        cout<<g[i].x<<"  "<<g[i].y<<endl;
    22     }
    23 }
    24 LL sum[maxn];
    25 bool cmp1(const node a,const node b){return a.x<b.x;}
    26 bool cmp2(const node a,const node b){return a.y<b.y;}
    27 void work(){
    28     sort(g+1,g+n+1,cmp1);
    29     memset(sum,0,sizeof(sum));
    30     for(int i=1;i<=n;i++) sum[i]=sum[i-1]+(LL)g[i].x;
    31     for(int i=1;i<=n;i++){
    32         g[i].sumx+=g[i].x*(i-1)-sum[i-1];
    33         g[i].sumx+=(sum[n]-sum[i])-(n-i)*g[i].x;
    34     }
    35     sort(g+1,g+n+1,cmp2);
    36     memset(sum,0,sizeof(sum));
    37     for(int i=1;i<=n;i++) sum[i]=sum[i-1]+g[i].y;
    38     for(int i=1;i<=n;i++){
    39         g[i].sumy+=g[i].y*(i-1)-sum[i-1];
    40         g[i].sumy+=(sum[n]-sum[i])-(n-i)*g[i].y;
    41     }
    42     LL ans=0x7fffffffffffffffll;
    43     for(int i=1;i<=n;i++){
    44         ans=min(g[i].sumx+g[i].sumy,ans);
    45     }
    46     cout<<ans/2<<endl;
    47 }
    48 int main(){
    49 //    freopen("a.in","r",stdin);
    50     init();
    51     work();
    52     return 0;
    53 }
    View Code

    BZOJ[1079] [SCOI2008]着色方案

    这个题可以用 记忆化搜索+哈希+map 水过,就是把每次剩下的所有颜色的个数除了上一个的颜色之外排序,然后哈希记录一下当前的贡献,当下次再遇到这个状态的时候,直接return就行了

     1 #include <map>
     2 #include <cmath>
     3 #include <cstdio>
     4 #include <cstring>
     5 #include <cstdlib>
     6 #include <iostream>
     7 #include <algorithm>
     8 # define mod 1000000007
     9 # define P 76543
    10 using namespace std;
    11 typedef long long LL;
    12 typedef unsigned long long ULL;
    13 void ot(){cout<<"****"<<endl;}
    14 void fen(){cout<<"----------------------------"<<endl;}
    15 ULL px[22];
    16 void beg(){px[0]=1; for(int i=1;i<=20;i++) px[i]=px[i-1]*P;}
    17 int n,tot;
    18 int Num[20];
    19 map<ULL,LL> ma;
    20 bool cmp(const int a,const int b){return a<b;}
    21 int cun[15];
    22 ULL HS(int x,int lst){
    23     ULL ret=0;
    24     for(int i=1;i<=x;i++){
    25         ret+=cun[i]*px[i];
    26     }
    27     return ret;
    28 }
    29 LL dfs(int x,int lst){
    30     if(x==tot+1){ return 1; }
    31     int tip=0; ULL hs;
    32     for(int i=1;i<=n;i++){
    33         if(i==lst) continue;
    34         cun[++tip]=Num[i];
    35     }
    36     sort(cun+1,cun+tip+1,cmp); cun[++tip]=Num[lst]; 
    37     hs=HS(tip,lst);
    38     if(ma.count(hs)){return ma[hs];}
    39     LL now=0;
    40     for(int i=1;i<=n;i++){
    41         if(i==lst || !Num[i]) continue;
    42         Num[i]--;
    43         now+=dfs(x+1,i);
    44         now%=mod;
    45         Num[i]++;
    46     }
    47     ma[hs]=now;
    48     return now;
    49 }
    50 int main(){
    51 //  freopen("a.in","r",stdin);
    52 //  freopen("ce.out","w",stdout);
    53     scanf("%d",&n);
    54     beg();
    55     for(int i=1;i<=n;i++) scanf("%d",&Num[i]),tot+=Num[i];
    56     LL ans=dfs(1,-1);
    57     cout<<ans<<endl;
    58     return 0;
    59 }
    View Code

    BZOJ[2839] 集合计数

    这个题就是可以先从n个里面选出K个,然后考虑剩下的元素的组成的集合,互没有交集的方案数,

    开始我想的是用一个f数组来递推,然后利用挡板法来求,后来发现并不能这么转移,因为有很多重复的情况没有办法去掉,然而正解是之前的题上试过很多次的不行的容斥原理,

    用f[i]表示剩下的元素组成交集大小至少是i的方案数,因为至少要选择i个,那就先乘一个C(n-K,i);然后剩下的(n-i-K)个元素有2^(n-i-K)个子集,每一个集合都可以选或者不选,但是不能都不选,因为当前的含义是把调出来的K个放在这些集合里,然后就能得到f[i]=C(n-K,i)*2^(2^(n-i-K)),然后偶加奇减,乘C(n,K)就是答案了

  • 相关阅读:
    morning
    周末,又见周末
    One Care, still Care
    Linux 下挂载硬盘的 方法
    Oracle 11g Alert log 文件位置的问题
    Oracle中 drop user 和 drop user cascade 的区别
    如何加快建 index 索引 的时间
    Oracle ADDM 自动诊断监视工具 介绍
    Vmware SERVER 简介
    Oracle Logminer 说明
  • 原文地址:https://www.cnblogs.com/FOXYY/p/7674242.html
Copyright © 2011-2022 走看看