zoukankan      html  css  js  c++  java
  • [校内训练20_06_03]ABC

    1.

    给你一个圆环,上面均匀分布着2N 个点,顺时针依次标为1~2N。
    现在把这些点分成N 对,然后把每一对点之间连一条线段。两个点被认为是互相可达的当且仅当可以从一个点开始,通过在线段上行走走到另一个点。连通块数指为将每一对互相可达的点之间连一条边形成一张图,这张图中的连通分量数量。
    现在有一些点对是确定的,请你回答所有可能的划分点对的方案中,连通块数的和是多少。N<=300

      1 #pragma GCC optimize 2
      2 #define mod 1000000007
      3 #define G2 500000004
      4 #include<bits/stdc++.h>
      5 using namespace std;
      6 typedef long long int ll;
      7 int n,m;
      8 int a[5555][2];
      9 ll f[5555],C[1555][1555],fac[5555];
     10 inline void add(ll&x,ll y)
     11 {
     12     x=(x+y)%mod;
     13 }
     14 inline void init()
     15 {
     16     f[0]=1;
     17     for(int i=1;i<=1000;++i)
     18         f[i]=f[i-1]*(2*i-1)%mod;
     19     fac[0]=1;
     20     for(int i=1;i<=1000;++i)
     21         fac[i]=fac[i-1]*i%mod;
     22     for(int i=0;i<=1000;++i)
     23     {
     24         C[i][0]=1;
     25         for(int j=1;j<=i;++j)
     26             C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
     27     }
     28 }
     29 int num[666],sumL[666],sumR[666];
     30 ll g[666],h[666];
     31 int cantL[666],cantR[666];
     32 bool to[666];
     33 inline ll get(int l,int r)
     34 {
     35     int s0=l-1,s1=2*n-r,s2=r-l-1;
     36     for(int i=1;i<=m;++i)
     37         if(a[i][0]==l&&a[i][1]!=r)
     38             return 0;
     39         else if(a[i][1]==r&&a[i][0]!=l)
     40             return 0;
     41         else if(a[i][0]==r||a[i][1]==l)
     42             return 0;
     43     int TI=0;
     44     for(int i=l-1;i>=1;--i)
     45         num[i]=++TI;
     46     for(int i=2*n;i>=r+1;--i)
     47         num[i]=++TI;
     48     for(int i=r-1;i>=l+1;--i)
     49         num[i]=++TI;
     50     ll s=0;
     51     memset(cantL,0,sizeof(cantL));
     52     memset(cantR,0,sizeof(cantR));
     53     memset(to,0,sizeof(to));
     54     memset(g,0,sizeof(g));
     55     memset(h,0,sizeof(h));
     56     for(int i=1;i<=m;++i)
     57     {
     58         if(a[i][0]==l&&a[i][1]==r)
     59             continue;
     60         to[num[a[i][0]]]=1;
     61         to[num[a[i][1]]]=1;
     62         int L=min(num[a[i][1]],num[a[i][0]]);
     63         int R=max(num[a[i][1]],num[a[i][0]]);
     64         ++cantL[L],--cantL[R];
     65         --cantR[L],++cantR[R];
     66     }
     67     for(int i=1;i<=s0+s1+s2;++i)
     68         sumL[i]=sumL[i-1]+(to[i]==0),cantL[i]+=cantL[i-1];
     69     cantR[s0+s1+s2+1]=0;
     70     for(int i=s0+s1+s2;i>=1;--i)
     71         cantR[i]+=cantR[i+1];
     72     sumR[s0+s1+s2+1]=0;
     73     for(int i=s0+s1+s2;i>=1;--i)
     74         sumR[i]=sumR[i+1]+(to[i]==0);
     75     if(sumL[s0]%2==0)
     76         g[s0]=f[sumL[s0]>>1];
     77     for(int i=s0+1;i<=s0+s1;++i)
     78     {
     79         if(cantL[i]||sumL[i]%2==1)
     80             continue;
     81         g[i]=f[sumL[i]>>1];
     82         for(int j=s0;j<i;++j)
     83         {
     84             if(cantL[j])
     85                 continue;
     86             if((sumL[i]-sumL[j])%2==0)
     87                 g[i]=(g[i]-g[j]*f[(sumL[i]-sumL[j])>>1]%mod+mod)%mod;
     88         }
     89     }
     90     if(sumR[s0+s1+1]%2==0)
     91         h[s0+s1+1]=f[sumR[s0+s1+1]>>1];
     92     for(int i=s0+s1;i>=s0;--i)
     93     {
     94         if(cantR[i]||sumR[i]%2==1)
     95             continue;
     96         h[i]=f[sumR[i]>>1];
     97         for(int j=i+1;j<=s0+s1+1;++j)
     98         {
     99             if(cantR[j])
    100                 continue;
    101             if((sumR[i]-sumR[j])%2==0)
    102                 h[i]=(h[i]-h[j]*f[(sumR[i]-sumR[j])>>1]%mod+mod)%mod;
    103         }
    104     }
    105     for(int i=s0;i<=s0+s1;++i)
    106         for(int j=i+1;j<=s0+s1+1;++j)
    107         {
    108             if(cantL[i]||cantR[j]||(sumL[j-1]-sumL[i])%2==1)
    109                 continue;
    110             else if(g[i]&&h[j])
    111                 add(s,g[i]*h[j]%mod*f[(sumL[j-1]-sumL[i])>>1]%mod);
    112         }
    113     return s;
    114 }
    115 inline void solve()
    116 {
    117     cin>>n>>m;
    118     for(int i=1;i<=m;++i)
    119     {
    120         cin>>a[i][0]>>a[i][1];
    121         if(a[i][0]>a[i][1])
    122             swap(a[i][0],a[i][1]);
    123     }
    124     ll ans=0;
    125     for(int i=1;i<=2*n;++i)
    126         for(int j=i+1;j<=2*n;++j)
    127             ans=(ans+get(i,j))%mod;
    128     cout<<ans<<endl;
    129 }
    130 int main()
    131 {
    132     freopen("count.in","r",stdin);
    133     freopen("count.out","w",stdout);
    134     ios::sync_with_stdio(false);
    135     init();
    136     int T;
    137     cin>>T;
    138     while(T--)
    139         solve();
    140     return 0;
    141 }
    142 /*
    143 2
    144 2 0
    145 20 10
    146 10 18
    147 11 17
    148 14 7
    149 4 6
    150 30 28
    151 19 24
    152 29 22
    153 25 32
    154 38 34
    155 36 39
    156 */
    View Code

    2.

    给你一张有重边无自环的图,共有n 个点,m 条边。每一条边正着走和反着走各有一个要花费的时间。
    请你求出在不走重边的情况下,从1 号点出发再回到1 号点至少需要多久。

     1 #include<bits/stdc++.h>
     2 #define ll long long
     3 #define lld long double
     4 using namespace std;
     5 template<typename tn> void read(tn &a){
     6     tn x=0,f=1; char c=' ';
     7     for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
     8     for(;isdigit(c);c=getchar()) x=x*10+c-'0';
     9     a=x*f;
    10 }
    11 const int N = 21000;
    12 int n,m;
    13 struct edge{int v,w,num;};
    14 class Graph{
    15 public:
    16     int n;
    17     vector<edge> e[N];
    18     int d[N],fr[N],pre[N];
    19     priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
    20     void init(int num){
    21         n=num;
    22     }
    23     void add(int x,int y,int z,int num=0){
    24         e[x].push_back({y,z,num});
    25     }
    26     void dij(){
    27         memset(d,63,sizeof(d));d[1]=0;
    28         q.push(make_pair(0,1));
    29         while(!q.empty()){
    30             int u=q.top().second,dist=q.top().first;q.pop();
    31             if(dist!=d[u]) continue;
    32             for(auto v:e[u])
    33                 if(d[v.v]>d[u]+v.w){
    34                     fr[v.v]=u==1?v.num:fr[u];
    35                     pre[v.v]=u;
    36                     d[v.v]=d[u]+v.w;
    37                     q.push(make_pair(d[v.v],v.v));
    38                 }
    39         }
    40     }
    41 }G1,G2;
    42 void getans(int x,int flag=0){
    43     if(x==1){cout<<1<<' ';return;}
    44     if(flag){
    45         getans(G1.pre[x],1);
    46         cout<<x<<' ';
    47         return;
    48     }
    49     if(G2.pre[x]>1){
    50         getans(G2.pre[x]);cout<<(x>n?1:x)<<' ';
    51     }
    52     else{
    53         for(int i=2;i<=n;i++)
    54             for(auto v:G1.e[i])
    55                 if(x>n){
    56                     if(v.v==1&&G1.fr[i]!=v.num&&G1.d[i]+v.w==G2.d[x]){
    57                         getans(i,1);
    58                         cout<<1<<' ';
    59                         return;
    60                     }
    61                 }
    62                 else{
    63                     if(v.v==x&&G1.fr[i]!=G1.fr[v.v]&&G1.d[i]+v.w==G2.d[x]){
    64                         getans(i,1);
    65                         cout<<x<<' ';
    66                         return;
    67                     }
    68                 }
    69     }
    70 }
    71 int main(){
    72     freopen("circuit.in","r",stdin);
    73     freopen("circuit.out","w",stdout);
    74     read(n);read(m);
    75     G1.init(n);
    76     for(int i=1;i<=m;i++){
    77         int x,y,z1,z2;read(x);read(y);read(z1);read(z2);
    78         G1.add(x,y,z1,i);
    79         G1.add(y,x,z2,i);
    80     }
    81     G1.dij();
    82     G2.init(n+1);
    83     for(int i=2;i<=n;i++)
    84         for(auto v:G1.e[i])
    85             if(v.v==1){
    86                 if(G1.fr[i]==v.num) G2.add(i,n+1,v.w);
    87                 else G2.add(1,n+1,G1.d[i]+v.w);
    88             }
    89             else{
    90                 if(G1.fr[i]==G1.fr[v.v]) G2.add(i,v.v,v.w);
    91                 else G2.add(1,v.v,G1.d[i]+v.w);
    92             }
    93     G2.dij();
    94     cout<<G2.d[n+1]<<'
    ';
    95     getans(n+1);
    96     cout<<'
    ';
    97     return 0;
    98 }
    View Code

    3.有n 只怪物,每只有一个生命值ai, 即要打ai 下才会死。所有的怪物外貌一样,无法分辨。
    你想要狩猎至少m 只怪物,并且你知道怪物的血量(但不能和怪物一一对应),求出最坏情况下最少的攻击次数。N<=1000

    对于这种奇怪的题目,一定要找到一些特殊的性质。

    我们先考虑m=1怎么做。那么我们会挑选一个选定的量x(当然是怪物的一个存在的血量),每次挑出一个怪物。若在x步内能解决问题,那么久停止。否则立刻换另一个怪物。

    可以发现,最优的策略一定在这里出现。因为如果存在一种策略,会在过程中改变这个选定的量x,那么一开始就应该改变。

    那么将a数组从大到小排序,答案为min{ai*i}。为什么要乘i?应为每次都可能选中一个大于x的怪物。

    现在m不为1。仍然是将a数组从大到小排序,我们现在选出一个大小为m的下标集合(下标从小到大拍好),表示我以此选定的量x。那么这种策略的答案为$a_{s_1}*{s_1}+sum_{i=2}^{m}{a_{s_i}*(s_i-s_{i-1})}$,理由和m=1是一样的。

    那么写出dp方程后,即可斜率优化。复杂度O(n^2)。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long double ld;
     4 const int maxn=2E3+5;
     5 const int inf=INT_MAX;
     6 int n,m,a[maxn];
     7 int f[maxn][maxn];
     8 int q[maxn][maxn],qL[maxn],qR[maxn];
     9 inline ld slope(int i1,int i2,int j)
    10 {
    11     return (ld)(f[i1][j]-f[i2][j])/(i1-i2);
    12 }
    13 inline int get(int i,int j,int k)
    14 {
    15     return f[k][j-1]+(i-k)*a[i];
    16 }
    17 inline void solve()
    18 {
    19     cin>>n>>m;
    20     for(int i=1;i<=n;++i)
    21         cin>>a[i];
    22     sort(a+1,a+n+1);
    23     reverse(a+1,a+n+1);
    24     for(int i=0;i<=n;++i)
    25         for(int j=0;j<=n;++j)
    26             f[i][j]=inf;
    27     f[0][0]=0;
    28     memset(q,0,sizeof(q));
    29     memset(qL,0,sizeof(qL));
    30     memset(qR,0,sizeof(qR));
    31     for(int i=0;i<=n;++i)
    32         qL[i]=1,qR[i]=0;
    33     qR[0]=1;
    34     q[0][1]=0;
    35     int ans=inf;
    36     for(int i=1;i<=n;++i)
    37         for(int j=i;j>=1;--j)
    38         {
    39             if(j==1)
    40                 f[i][j]=get(i,j-1,0);
    41             else
    42             {
    43                 while(qL[j-1]<qR[j-1]&&slope(q[j-1][qR[j-1]-1],q[j-1][qR[j-1]],j-1)>=a[i])
    44                     --qR[j-1];
    45                 f[i][j]=get(i,j,q[j-1][qR[j-1]]);
    46             }
    47             while(qL[j]<qR[j]&&slope(q[j][qR[j]-1],q[j][qR[j]],j)>=slope(q[j][qR[j]],i,j))
    48                 --qR[j];
    49             q[j][++qR[j]]=i;
    50             ans=min(ans,f[i][m]);
    51         }
    52 //    for(int i=1;i<=n;++i,cout<<endl)
    53 //        for(int j=1;j<=i;++j)
    54 //            cout<<f[i][j]<<" ";
    55     cout<<ans<<endl;
    56 }
    57 int main()
    58 {
    59 //    freopen("hunt.in","r",stdin);
    60 //    freopen("hunt.out","w",stdout);
    61     ios::sync_with_stdio(false);
    62     int T;
    63     cin>>T;
    64     while(T--)
    65         solve();
    66     return 0;
    67 }
    View Code
  • 相关阅读:
    129 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 03 饿汉模式 VS 懒汉模式 02 懒汉式的代码实现
    128 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 03 饿汉模式 VS 懒汉模式 01 饿汉式的代码实现
    127 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 02 单例模式概述 01 单例模式的定义和作用
    126 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 01 设计模式概述 01 设计模式简介
    125 01 Android 零基础入门 02 Java面向对象 05 Java继承(下)05 Java继承(下)总结 01 Java继承(下)知识点总结
    leetcode-----121. 买卖股票的最佳时机
    leetcode-----104. 二叉树的最大深度
    Json串的字段如果和类中字段不一致,如何映射、转换?
    Mybatis-Plus的Service方法使用 之 泛型方法default <V> List<V> listObjs(Function<? super Object, V> mapper)
    模糊查询
  • 原文地址:https://www.cnblogs.com/GreenDuck/p/13084990.html
Copyright © 2011-2022 走看看