HL DAY5

· · 个人记录

今天还是有点SB 换根式子没推出来

然后明明做过换根的题 但是不知道自己在干什么乱搞T1

真是个SB

T1:

最裸的暴力就是O(n^4)

直接枚举每个子串情况

然后暴力判断求解

考虑一下优化

其实有个问题就是

这个题真的跟字符串有关吗????

不就是昨天考了字符串 然后老师迷惑下我们

考虑下五千的数据应该是O(n^2)的做法

题目要求是记录子串中位置相同 然后相同位置的个数

那么我们考虑直接两个串一个一个位置匹配

然后计算一下对答案的贡献

我们可以用数学的方法,在找到两个相同的字符后直接算出答案。将两个字符所在的位置对齐。讲两个字符串分别分出两个部分。一个左边一个右边。先算出两个字符串的左边的最小值,再算出两个字符串的右边的最小值。右边的界限是一定在右边的最小值中的。左边的界限是一定在左边的最小值中。所以方法为左边的数*右边的数。(包含当前数)

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
char a[N],b[N];
int n;
long long num,ans;
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-'){
            f=-1;
        }
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
int main(){
    freopen("strfun.in","r",stdin);
    freopen("strfun.out","w",stdout);
    n=read();
    cin>>a+1>>b+1;
    for(int i=1;i<=n;i++){
        num+=(i*i);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(a[i]==b[j]){
                ans+=min(i,j)*min(n-i+1,n-j+1); 
            }
        }
    }
//  printf("%d",ans);
    printf("%.6lf",(double )ans/(double )num);  
    return 0;
}

对 100%的数据, 可以发现若 a < b,上面那个式子的值是可以确定的,所以我们转而考 虑枚举 s 串的一个位置 a,看 t 串有多少个 b 的位置使得 s[a] = t[b],且 b > a,这样我 们可以用一个前缀和数组优化,即可通过此题。 复杂度 O(n)

#include <bits/stdc++.h>
using namespace std;
const int N=1E6+10;
long long ans,num;
int n,sa[N],sb[N];
char a[N],b[N];
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-'){
            f=-1;
        }
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
int main(){
    freopen("strfun.in","r",stdin);
    freopen("strfun.out","w",stdout);
    n=read();
    for(int i=1;i<=n;i++){
        num+=i*i;
    }
    cin>>a+1>>b+1;
    for(int i=1;i<=n;i++){
        sa[a[i]-'A']+=i; 
        ans+=sb[a[i]-'A']*(n-i+1);
        sb[b[i]-'A']+=i;
        ans+=sa[b[i]-'A']*(n-i+1);
    }
    printf("%.6lf",(double )ans/(double )num);
    return 0;
}

T2:

考场上手玩了一下数据

然后搞出来一个玄学的做法

具体实现?

就是我们从1号节点开始DFS树

然后我们统计一下从一号节点的树上前缀和

这样的话我们只要再考虑下再次DFS时 通过已知的从1开始的

推一下式子

结果发现 只要记录下开始的根 然后用LCA推出来了个式子

ans+=(dis[root]+dis[v]-2*dis[Lca(root,v)]+a[Lca(root,v)]);

然后一开始测试的时候发现小数据过了

大样例没过

输出是负的

然后发现没lld

改过之后就A了

真的没想到

过于神奇

然后最后推了推换根式子 发现失败了

就50分吧..

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1E6+10;
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-'){
            f=-1;
        }
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
struct edge{
    int next,to,w;
}e[N];
int head[N],cnt,dis[N],a[N],n,ans,f[N][21],dep[N],t;
inline void add(int x,int y,int w){
    e[++cnt].next=head[x];
    e[cnt].to=y;
    e[cnt].w=w;
    head[x]=cnt;
}
//inline void dfs1(int x,int fa){
//  for(int i=head[x];i;i=e[i].next){
//      int v=e[i].to;
//      if(v==fa) continue;
//      if(dis[v]) continue;
//      dis[v]=dis[x]+a[v];
//      dfs1(v,x);
//  }
//}
queue<int >q;
int last=0;
inline void bfs(){
    queue<int>q; 
    q.push(1);
    dep[1]=1;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].to;
            if(dep[v]) continue;
            dep[v]=dep[u]+1;
            dis[v]=dis[u]+a[v];
            f[v][0]=u;
            for(int j=1;j<=t;j++){
                f[v][j]=f[f[v][j-1]][j-1];
            }
            q.push(v);
        }
    }
}
inline int Lca(int x,int y){
    if(dep[x]>dep[y]) swap(x,y);
    for(int i=t;i>=0;i--){
        if(dep[f[y][i]]>=dep[x]) y=f[y][i];
    }
    if(x==y) return x;
    for(int i=t;i>=0;i--){
        if(f[x][i]!=f[y][i]){
            x=f[x][i];
            y=f[y][i];
        }
    }
    return f[x][0];
}
inline  void  dfs2(int root,int x,int fa,int la){
    for(int i=head[x];i;i=e[i].next){
        int v=e[i].to;
        if(v==fa) continue;
        if(e[i].w!=la){
            q.push(v);  
            dfs2(root,v,x,e[i].w); 
            ans+=(dis[root]+dis[v]-2*dis[Lca(root,v)]+a[Lca(root,v)]);
        }
    }   
}
signed main(){
    freopen("path.in","r",stdin);
    freopen("path.out","w",stdout);
    n=read();
    t=log2(n);
    for(int i=1;i<=n;i++){
        a[i]=read();
    }
    for(int i=1;i<n;i++){
        int u,v,w;
        u=read();
        v=read();
        w=read();
        add(u,v,w);
        add(v,u,w);
    }
    bfs();//O(n)
//  dfs1(1,0);
//  for(int i=1;i<=n;i++){
//      cout<<a[i]<<endl;
//  }
    for(int i=1;i<=n;i++){//Nlogn
//      queue<int >q;
//      last=0;
        dfs2(i,i,0,0);
//      while(!q.empty()){
//          int u=q.front();
////            cout<<u<<" ";
//          q.pop();
//          ans+=(dis[i]+dis[u]-2*dis[Lca(i,u)]+a[Lca(i,u)]);
//      }       
//      cout<<endl;
    }
    printf("%lld",ans/2);
    return 0;
}

正解好像是树形DP ??

考虑学一学点分治

T3:

什么鬼畜的生成树计数??

图计数我还不会

直接放弃先

还需要prufer序...

我佛了

放下STD:

#include <cstdio>
typedef long long ll;
const int Mod = 1004535809;
const int MaxN = 110;
int n, dp[MaxN][MaxN][MaxN], A[MaxN], fac[MaxN], Ie[MaxN];
int pow(int x, int k) {
    ll res = 1, r = x;
    for (; k; k >>= 1, r = r * r % Mod)
        if (k & 1) res = res * r % Mod;
    return res;
}
int main() {
    freopen("tree.in", "r", stdin);
    freopen("tree.out", "w", stdout);
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        if (A[i] >= n) A[i] = n - 1;
    }

    fac[0] = 1;
    for (int i = 1; i <= n; ++i) fac[i] = (ll)fac[i - 1] * i % Mod;

    Ie[n] = pow(fac[n], Mod - 2);
    for (int i = n; i; --i) Ie[i - 1] = (ll)Ie[i] * i % Mod;

    dp[0][0][0] = 1;
    for (int i = 1; i <= n; ++i) {
        for (int j = 0; j < i; ++j) {
            for (int k = 0; k <= n; ++k) 
                if (dp[i - 1][j][k]) {
                    if ((dp[i][j][k] += dp[i - 1][j][k]) >= Mod) dp[i][j][k] -= Mod;
                    for (int c = 0; c < A[i]; ++c) {
                        if (k + c > n) break;
                        if ((dp[i][j + 1][k + c] += (ll)dp[i - 1][j][k] * Ie[c] % Mod) >= Mod) dp[i][j + 1][k + c] -= Mod;
                    }
                }
        }
    }
    printf("%d ", n);
    for (int i = 2; i <= n; ++i) printf("%d ", (ll)dp[n][i][i - 2] * fac[i - 2] % Mod);
    fclose(stdin);
    fclose(stdout);
}