zoukankan      html  css  js  c++  java
  • 2020杭电多校第六场

    T1001 Road To The 3rd Building

    总的方案数有 n(n+1)/2 种。然后考虑每种方案的贡献:

    设s[i]为前缀和,Ans是总的贡献,ans[i]是中间过程的累加和。

    ans[i] = s[n-i+1] - s[i-1] + ans[i-1]

    Ans= $sum_{i=1}^n$ ans[i]/i

    期望就是总的贡献除以总的方案数了。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int mod= 1e9+7;
     5 const int N=2e5+10;
     6 ll s[N];
     7 ll ans[N];
     8 ll quick_pow(ll x,ll y){
     9     ll res=1;
    10     while(y){
    11         if(y&1) res=res*x%mod;
    12         x=x*x%mod;
    13         y>>=1;
    14     }
    15     return res;
    16 }
    17 int main()
    18 {
    19     int T;
    20     scanf("%d",&T);
    21     while(T--){
    22         ll Ans=0;
    23         ll n;
    24         scanf("%lld",&n);
    25         for(int i=1;i<=n;i++){
    26             scanf("%lld",&s[i]);
    27             s[i]=(s[i]+s[i-1])%mod;
    28         }
    29         for(int i=1;i<=n;i++){
    30             ans[i]=(s[n-i+1]-s[i-1]+ans[i-1]+mod)%mod;
    31             ll inv=quick_pow(i,mod-2);
    32             Ans=(Ans+ans[i]*inv%mod)%mod;
    33         }
    34         ll inv=quick_pow(n*(n+1)%mod,mod-2);
    35         Ans=(Ans*2%mod*inv)%mod;
    36         printf("%lld
    ",Ans);
    37     }
    38     return 0;
    39 }

    T1002 Little Rabbit's Equation

    先找出方程最小可能是几进制(通过方程中的数字、字母判断),然后从 最小可能的进制 到16进制循环模拟,找到符合方程的最小进制。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 char s[30];
     5 int main()
     6 {
     7     while(~scanf("%s",s+1)){
     8         int len=strlen(s+1);
     9         int mx=2;
    10         for(int i=1;i<=len;i++){
    11             if(s[i]>='0'&&s[i]<='9')
    12                 mx=max(mx,s[i]-48+1);
    13             if(s[i]>='A'&&s[i]<='F')
    14                 mx=max(mx,s[i]-'A'+10+1);
    15         }
    16         bool flag=0;
    17         for(ll k=mx;k<=16;k++){
    18             ll x=0,y=0,z=0;
    19             int i=1,j;
    20             while(s[i]!='+'&&s[i]!='-'&&s[i]!='*'&&s[i]!='/'){
    21                 if(s[i]>='A'){
    22                     x=x*k+s[i]-'A'+10;
    23                 }
    24                 else x=x*k+s[i]-48;
    25                 i++;
    26             }
    27             if(s[i]=='+') j=1;
    28             else if(s[i]=='-') j=2;
    29             else if(s[i]=='*') j=3;
    30             else j=4;
    31             i++;
    32             while(s[i]!='='){
    33                 if(s[i]>='A'){
    34                     y=y*k+s[i]-'A'+10;
    35                 }
    36                 else y=y*k+s[i]-48;
    37                 i++;
    38             }
    39             i++;
    40             while(i<=len){
    41                 if(s[i]>='A'){
    42                     z=z*k+s[i]-'A'+10;
    43                 }
    44                 else z=z*k+s[i]-48;
    45                 i++;
    46             }
    47             //printf("%lld %lld %lld
    ",x,y,z);
    48             if(j==1&&x+y==z){
    49                 flag=1;
    50                 printf("%lld
    ",k);
    51                 break;
    52             }
    53             if(j==2&&x-y==z){
    54                 flag=1;
    55                 printf("%lld
    ",k);
    56                 break;
    57             }
    58             if(j==3&&x*y==z){
    59                 flag=1;
    60                 printf("%lld
    ",k);
    61                 break;
    62             }
    63             if(j==4&&x==y*z){
    64                 flag=1;
    65                 printf("%lld
    ",k);
    66                 break;
    67             }
    68         }
    69         if(flag==0) printf("-1
    ");
    70     }
    71     return 0;
    72 }

    T1005 Fragrant numbers

    区间dp,通过观察,只需要前13个数便可代表所有的数来构造前5000个数(当然,数不一定全部构造出来)。

    dp[ i ][ j ][ k ] 表示 i - j 区间能否构造出k。

    对于每个询问,只需要找到dp[ 1 ][ i ][ n ] = 1 的最小的右端点 i 。 

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int N=5010;
     5 const int a[13]={1,1,4,5,1,4,1,9,1,9,1,1,4};
     6 bool dp[20][20][N];
     7 int ans[N];
     8 int getnum(int l,int r){
     9     int num=0;
    10     for(int i=l;i<=r;i++)
    11         num=num*10+a[i-1];
    12     return num;
    13 }
    14 void Prepare(){
    15     for(int i=1;i<=13;i++){
    16         dp[i][i][a[i-1]]=1;
    17     }
    18     for(int len=1;len<13;len++){
    19         for(int i=1;i+len<=13;i++){
    20             int j=i+len;
    21             if(len<4){
    22                 int x=getnum(i,j);
    23                 if(x<=5000) dp[i][j][x]=1;
    24             }
    25             for(int k=i;k<j;k++){
    26                 for(int u=1;u<=5000;u++){
    27                     if(dp[i][k][u]==0) continue;
    28                     for(int v=1;v<=5000;v++){
    29                         if(dp[k+1][j][v]==0) continue;
    30                         if(u+v<=5000) dp[i][j][u+v]=1;
    31                         if(u*v<=5000) dp[i][j][u*v]=1;
    32                         if(u+v>5000&&u*v>5000) break;
    33                     }
    34                 }
    35             }
    36         }
    37     }
    38     memset(ans,-1,sizeof(ans));
    39     for(int i=13;i>=1;i--)
    40         for(int j=1;j<=5000;j++)
    41             if(dp[1][i][j])
    42                 ans[j]=i;
    43 }
    44 int main()
    45 {
    46     Prepare();
    47     int T;
    48     scanf("%d",&T);
    49     while(T--){
    50         int n;
    51         scanf("%d",&n);
    52         printf("%d
    ",ans[n]);
    53     }
    54     return 0;
    55 }

    T1006 A Very Easy Graph Problem

    有一个明显的结论 $sum_{i=1}^n$ $2^i$ < $2^{n+1}$

    所以可以从第一条边开始建立最小生成树,因为根据以上结论,每两个点之间的最短路经过的边一定在最小生成树上。

    这样可以统计最小生成树上每条边的贡献(经过的次数*边长)。我的方法是直接两次dfs,第一次统计子树中0和1的个数,第二次计算贡献。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int mod=1e9+7;
     5 const int N=1e5+10;
     6 const int M=2e5+10;
     7 int head[N],to[M],nxt[M];
     8 ll w[M];
     9 int tot;
    10 int n,m;
    11 int a[N];
    12 int s[N];
    13 ll num0[N],num1[N];
    14 ll ans;
    15 void init(){
    16     tot=0;
    17     ans=0;
    18     memset(head,0,sizeof(head));
    19 }
    20 int find_set(int x){
    21     if(x!=s[x]) return s[x]=find_set(s[x]);
    22     return s[x];
    23 }
    24 inline void add(int u,int v,ll x){
    25     to[++tot]=v,nxt[tot]=head[u],w[tot]=x,head[u]=tot;
    26 }
    27 void dfs(int u,int fa){
    28     if(a[u]==0) num0[u]=1,num1[u]=0;
    29     else num1[u]=1,num0[u]=0;
    30     for(int i=head[u];i;i=nxt[i]){
    31         int v=to[i];
    32         if(v==fa) continue;
    33         dfs(v,u);
    34         num0[u]+=num0[v];
    35         num1[u]+=num1[v];
    36     }
    37 }
    38 void dfs2(int u,int fa){
    39     for(int i=head[u];i;i=nxt[i]){
    40         int v=to[i];
    41         if(v==fa) continue;
    42         ans=(ans+(num0[v]*(num1[1]-num1[v]+mod)%mod+num1[v]*(num0[1]-num0[v]+mod)%mod)*w[i]%mod)%mod;
    43         dfs2(v,u);
    44     }
    45 }
    46 int main()
    47 {
    48     int T;
    49     scanf("%d",&T);
    50     while(T--){
    51         init();
    52         scanf("%d%d",&n,&m);
    53         for(int i=1;i<=n;i++){
    54             scanf("%d",&a[i]);
    55             s[i]=i;
    56         }
    57         ll val=1;
    58         for(int i=1;i<=m;i++){
    59             int u,v;
    60             scanf("%d%d",&u,&v);
    61             val=val*2%mod;
    62             int x=find_set(u),y=find_set(v);
    63             if(x!=y){
    64                 s[y]=x;
    65                 add(u,v,val);
    66                 add(v,u,val);
    67             } 
    68         }
    69         dfs(1,0);
    70         dfs2(1,0);
    71         printf("%lld
    ",ans);
    72     }
    73     return 0;
    74 }

    T1009 Divisibility

    在b进制下,一个数被x整除的充要条件是所有位上的数加起来可以被x整除,则(b-1)是x的倍数。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int mod= 998244353;
     5 
     6 int main()
     7 {
     8     int T;
     9     scanf("%d",&T);
    10     while(T--){
    11         ll b,x;
    12         scanf("%lld%lld",&b,&x);
    13         if((b-1)%x==0){
    14             printf("T
    ");
    15         }
    16         else printf("F
    ");
    17     }
    18     return 0;
    19 }

    T1010 Expectation

    先用矩阵树定理求出所有生成树的个数。

    然后进行二进制拆位。即对于边权的每一位,找出边权的那一位为1的所有边,再次用矩阵树定理求出该位为1的所有边的生成树的个数,乘上该位的值,从而算出每一位的贡献。

    把每一位的贡献加起来除以生成树的总个数,便是期望。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int N=110;
     5 const int M=1e4+10;
     6 const int mod=998244353;
     7 struct edge{
     8     int from,to;
     9     ll d;
    10 }e[M];
    11 ll a[N][N];
    12 ll ans;
    13 int n,m;
    14 ll quick_pow(ll x,ll y){
    15     ll res=1;
    16     while(y){
    17         if(y&1) res=res*x%mod;
    18         x=x*x%mod;
    19         y>>=1;
    20     }
    21     return res;
    22 }
    23 void work(){
    24     for(int i=2;i<=n;i++){
    25         if(!a[i][i])
    26         for(int j=i+1;j<=n;j++){
    27             if(a[j][i]){
    28                 ans=-ans;
    29                 swap(a[i],a[j]);
    30                 break;
    31             }
    32         }
    33         ll inv=quick_pow(a[i][i],mod-2);
    34         for(int j=i+1;j<=n;j++){
    35             ll tmp=a[j][i]*inv%mod;
    36             for(int k=i;k<=n;k++){
    37                 a[j][k]=(a[j][k]-a[i][k]*tmp%mod+mod)%mod;
    38             }
    39         }
    40     }
    41 }
    42 void solve(ll lim){
    43     ans=1;
    44     for(int i=1;i<=n;i++)
    45         for(int j=1;j<=n;j++)
    46             a[i][j]=0;
    47     for(int i=1;i<=m;i++){
    48         int u=e[i].from,v=e[i].to;
    49         ll w=e[i].d;
    50         if(!(w&lim)) continue;
    51         a[u][u]++;
    52         a[v][v]++;
    53         a[u][v]--;
    54         a[v][u]--;
    55     }
    56     work();
    57     for(int i=2;i<=n;i++)
    58         ans=(ans*a[i][i])%mod;
    59     ans=(ans%mod+mod)%mod;
    60 }
    61 int main()
    62 {
    63     int T;
    64     scanf("%d",&T);
    65     while(T--){
    66         scanf("%d%d",&n,&m);
    67         for(int i=1;i<=m;i++){
    68             scanf("%d%d%lld",&e[i].from,&e[i].to,&e[i].d);
    69         }
    70         ll x=0;
    71         for(int i=0;i<30;i++){
    72             ll lim=(1<<i);
    73             solve(lim);
    74             x=(x+lim*ans%mod)%mod;
    75         }
    76         solve((1<<30)-1);
    77         ll sum=ans;
    78         ll inv=quick_pow(sum,mod-2);
    79         printf("%lld
    ",x*inv%mod);
    80     }
    81     return 0;
    82 }
  • 相关阅读:
    WPF复杂形状按钮
    (WPF)360安全卫士界面设计
    WPF图标拾取器
    WPF透明窗体制作
    空间分析开源库GEOS
    GIS开源程序收集
    flask 链接 url_for()
    自定制404错误页码
    Flask 模板语言
    flask路由和视图和cookie
  • 原文地址:https://www.cnblogs.com/--HY--/p/13491403.html
Copyright © 2011-2022 走看看