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
  • 相关阅读:
    Java类加载文章2(z)
    Java类加载文章1(z)
    Java类加载文章2(z)
    网页的文档对象模型
    网页元素的比例长度
    CSS 中三栏布局的实现
    CSS 中双栏布局的实现
    在浏览器中打开本地文件1
    Oracle Oracle UTL_RAW类
    SVN完整安装及简略使用
  • 原文地址:https://www.cnblogs.com/GreenDuck/p/13084990.html
Copyright © 2011-2022 走看看