zoukankan      html  css  js  c++  java
  • JSOI2018R2题解

    D1T1:潜入行动

    裸的树上DP。f[i][j][0/1][0/1]表示以i为根的子树放j个设备,根有没有放,根有没有被子树监听,的方案数。转移显然。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     4 typedef long long ll;
     5 using namespace std;
     6 
     7 const int N=100010,mod=1e9+7;
     8 ll tmp[110][2][2];
     9 int n,k,cnt,u,v,sz[N],dp[N][110][2][2],h[N],to[N<<1],nxt[N<<1];
    10 
    11 void ins(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
    12 void add(int &x,ll y){ if (x+y>=mod) x=x+y-mod; else x=x+y; }
    13 
    14 void dfs(int x,int fa){
    15     sz[x]=1; dp[x][1][1][0]=1; dp[x][0][0][0]=1; 
    16     for (int i=h[x]; i; i=nxt[i]){
    17         int v=to[i];
    18         if (v==fa) continue;
    19         dfs(v,x);
    20         int tx=min(k,sz[x]),tv=min(k,sz[v]);
    21         rep(j,0,tx) rep(a,0,1) rep(b,0,1)
    22             tmp[j][a][b]=dp[x][j][a][b],dp[x][j][a][b]=0;
    23         rep(j,0,tx){
    24             for(int a=0; a<=tv && j+a<=k; a++){
    25                 add(dp[x][j+a][0][0],tmp[j][0][0]*dp[v][a][0][1]%mod);
    26                 add(dp[x][j+a][0][1],(tmp[j][0][0]*dp[v][a][1][1]+tmp[j][0][1]*(dp[v][a][0][1]+dp[v][a][1][1]))%mod);
    27                 add(dp[x][j+a][1][0],tmp[j][1][0]*(dp[v][a][0][0]+dp[v][a][0][1])%mod);
    28                 add(dp[x][j+a][1][1],(tmp[j][1][0]*(dp[v][a][1][0]+dp[v][a][1][1])+tmp[j][1][1]*(dp[v][a][0][0]+dp[v][a][1][0])+tmp[j][1][1]*(dp[v][a][0][1]+dp[v][a][1][1]))%mod);
    29             }
    30         }
    31         sz[x]+=sz[v];
    32     }
    33 }
    34 
    35 int main(){
    36     freopen("action.in","r",stdin);
    37     freopen("action.out","w",stdout);
    38     scanf("%d%d",&n,&k);
    39     rep(i,2,n) scanf("%d%d",&u,&v),ins(u,v),ins(v,u);
    40     dfs(1,-1);
    41     printf("%d
    ",(dp[1][k][1][1]+dp[1][k][0][1])%mod);
    42     return 0;
    43 }
    D1T1

    D2T2:防御网络

    https://blog.csdn.net/scar_lyw/article/details/80410420

    首先连接环的桥边的贡献很好算,tarjan过程中可直接求出。然后对于每一个环,求出环上被选中边数的期望。
    一个环被选中的边,一定是环长减去最大的一个空隙。我们枚举环上的[s,s+len]中的点被选中(一个点被选中当且仅当子图S中包含这个点或这个点连出的外向树中的点)。设DP状态dp[s][len][k]表示[s,s+len]中有点且这段的最大空隙为k的方案数。求出dp数组后贡献就很容易求得了,注意还有一个空隙是环长-len。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     4 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
     5 using namespace std;
     6 
     7 const int N=1010,mod=1e9+7;
     8 int n,m,u,v,cnt,ans,f[N],p2[N],sz[N],vis[N],fa[N];
     9 int dp[N][2],sm[N][2],h[N],to[N],nxt[N],dep[N];
    10 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
    11 
    12 int ksm(int a,int b){
    13     int res=1;
    14     for (; b; a=1ll*a*a%mod,b>>=1)
    15         if (b & 1) res=1ll*res*a%mod;
    16     return res;
    17 }
    18 
    19 void calc(int s,int len,int n){
    20     rep(i,s-1,n) dp[i][0]=dp[i][1]=sm[i][0]=sm[i][1]=0;
    21     dp[s][0]=sm[s][0]=f[s];
    22     rep(i,s+1,n){
    23         int l=max(s,i-len+1)-1;
    24         if (i-len>=s) dp[i][1]=(dp[i][1]+1ll*(dp[i-len][0]+dp[i-len][1])*f[i])%mod;
    25         dp[i][1]=(dp[i][1]+1ll*f[i]*(sm[i-1][1]-sm[l][1]+mod))%mod;
    26         dp[i][0]=(dp[i][0]+1ll*f[i]*(sm[i-1][0]-sm[l][0]+mod))%mod;
    27         sm[i][0]=(sm[i-1][0]+dp[i][0])%mod; sm[i][1]=(sm[i-1][1]+dp[i][1])%mod;
    28         ans=(ans+1ll*min(i-s,n-len)*dp[i][1])%mod;
    29     }
    30 }
    31 
    32 void solve(int u,int v){
    33     int cur=v,lst=0,tot=0;
    34     for (; cur!=u; lst=cur,cur=fa[cur])
    35         f[++tot]=p2[sz[cur]-sz[lst]],vis[cur]=1;
    36     f[++tot]=p2[n-sz[lst]];
    37     rep(i,1,tot-1) rep(j,1,tot-i) calc(i,j,tot);
    38 }
    39 
    40 void dfs(int x){
    41     dep[x]=dep[fa[x]]+1; sz[x]=1;
    42     For(i,x) if (!dep[k=to[i]]) fa[k]=x,dfs(k),sz[x]+=sz[k];
    43         else if (dep[k]>dep[x]) solve(x,k);
    44 }
    45 
    46 int main(){
    47     freopen("defense.in","r",stdin);
    48     freopen("defense.out","w",stdout);
    49     scanf("%d%d",&n,&m);
    50     rep(i,1,m) scanf("%d%d",&u,&v),add(u,v),add(v,u);
    51     p2[0]=1; rep(i,1,n) p2[i]=p2[i-1]*2ll%mod;
    52     rep(i,1,n) p2[i]--;
    53     dfs(1);
    54     rep(i,2,n) if (!vis[i]) ans=(ans+1ll*p2[sz[i]]*p2[n-sz[i]])%mod;
    55     ans=1ll*ans*ksm(p2[n]+1,mod-2)%mod;
    56     printf("%d
    ",ans);
    57     return 0;
    58 }
    D2T2

    D1T3:绝地反击

    如果确定这个正n边形的话,二分+Dinic就好了。退火/爬山旋转正n边形即可。

    正解是网络流退流,未看。

    D2T1:部落战争

    https://www.cnblogs.com/HocRiser/p/10268249.html

    D2T2:扫地机器人

    留坑。

    D2T3:军训列队

    显然集合后每个人的相对位置可以不改变,那么把所求的式子列出来就会发现是一些定值加上关于每个人的坐标和集合点的差的绝对值的数。拆成两部分,显然左半部分向右走,右半部分向左走。

    在主席树上二分这个分界点,维护区间中点的坐标和,剩下的直接求解。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     4 #define lson ls[x],L,mid
     5 #define rson rs[x],mid+1,R
     6 typedef long long ll;
     7 using namespace std;
     8 
     9 const int N=500010,M=12500010;
    10 ll c,sum[N],sm[M];
    11 int n,Q,m,l,r,k,K,nd,a[N],rt[N],v[M],ls[M],rs[M];
    12 
    13 void ins(int y,int &x,int L,int R,int k){
    14     x=++nd; ls[x]=ls[y]; rs[x]=rs[y]; v[x]=v[y]+1; sm[x]=sm[y]+k;
    15     if (L==R) return;
    16     int mid=(L+R)>>1;
    17     if (k<=mid) ins(ls[y],lson,k); else ins(rs[y],rson,k);
    18 }
    19 
    20 int que(int x,int y,int L,int R,int k){
    21     if (L==R){ c+=sm[x]-sm[y]; return v[x]-v[y]; }
    22     int mid=(L+R)>>1,t=v[ls[x]]-v[ls[y]];
    23     if (k+t-1<mid) return que(ls[x],ls[y],L,mid,k);
    24     else{
    25         c+=sm[ls[x]]-sm[ls[y]];
    26         return v[ls[x]]-v[ls[y]]+que(rs[x],rs[y],mid+1,R,k+t);
    27     }
    28 }
    29 
    30 int main(){
    31     freopen("line.in","r",stdin);
    32     freopen("line.out","w",stdout);
    33     scanf("%d%d",&n,&Q);
    34     rep(i,1,n) scanf("%d",&a[i]),m=max(m,a[i]),sum[i]=sum[i-1]+a[i];
    35     rep(i,1,n) ins(rt[i-1],rt[i],1,m,a[i]);
    36     while (Q--){
    37         scanf("%d%d%d",&l,&r,&k); c=0;
    38         int tot=que(rt[r],rt[l-1],1,m,k),len=r-l+1;
    39         ll s1=1ll*tot*k+1ll*tot*(tot-1)/2-c;
    40         ll s2=sum[r]-sum[l-1]-c-1ll*(len-tot)*k-1ll*(tot+len-1)*(len-tot)/2;
    41         printf("%lld
    ",s1+s2);
    42     }
    43     return 0;
    44 }
    D2T3
  • 相关阅读:
    IIS编译器错误信息: CS0016:未能写入输出文件
    asp.net发布到IIS中出现错误:处理程序“PageHandlerFactory-Integrated”在其模块列表中有一个错误模块“ManagedPipelineHandler”
    js 入门
    gridview中 编辑列 要点两次才能出现编辑文本框
    菜鸟解决“子页面关闭刷新父页面局部”问题的历程
    Response.Redirect与Server.Transfer区别
    5天玩转C#并行和多线程编程 —— 第一天 认识Parallel
    C#中在WebClient中使用post发送数据实现方法
    最全面的常用正则表达式大全
    CSS中cursor的pointer 与 hand
  • 原文地址:https://www.cnblogs.com/HocRiser/p/10308048.html
Copyright © 2011-2022 走看看