zoukankan      html  css  js  c++  java
  • 2016ACM/ICPC亚洲区沈阳站-重现赛

    C.Recursive sequence

    求ans(x),ans(1)=a,ans(2)=b,ans(n)=ans(n-2)*2+ans(n-1)+n^4

    如果直接就去解。。。很难,毕竟不是那种可以直接化成矩阵的格式,我们也因为这个被卡很长时间

    事实上可以把这道式子化成几个基本元素的格式,然后就容易组合了,比如ans(n-2)*2+ans(n-1)+(n-1)^4+4*(n-1)^3+6*(n-1)^2+4*(n-1)^1+1

    包含了所有的基本组成形式,化绝对为相对,并且除了一个n-2其他都是n-1

    然后就是矩阵乘时间了

    #include <cstdio>
    #include <cstdlib>
    #include <algorithm>
    #include <cmath>
    #include <iostream>
    #include <cstring>
    
    using namespace std;
    
    typedef long long int ll;
    const ll mod = 2147493647;
    
    //定义矩阵乘法 
    struct matrix{
        ll arr[7][7];
        matrix operator*(matrix b){
            matrix ans;
            ll tmp;
            for(int i=0; i<7; i++)
                for(int j=0; j<7; j++){
                    ans.arr[i][j] = 0;
                    for(int k=0; k<7; k++){
                        tmp = (arr[i][k]*b.arr[k][j])%mod;
                        ans.arr[i][j] = (ans.arr[i][j] + tmp)%mod;
                    }        
                }
            return ans;
        }
    };
    
    //矩阵快速幂 
    matrix quick_pow(matrix a,ll N){
        matrix ans;
        memset(ans.arr,0,sizeof(ans.arr));
        for(int i=0; i<7; i++)
            ans.arr[i][i] = 1;
        while(N){
            if(N&1)
                ans = ans*a;
            a = a*a;
            N /= 2;; 
        }
        return ans;
    }
    
    int main(){
        
        matrix a;
        memset(a.arr,0,sizeof(a.arr));
        a.arr[0][1] = 1;
        a.arr[1][1] = a.arr[1][2] = a.arr[1][6] = 1;
        a.arr[2][2] = a.arr[2][6] = 1;
        a.arr[1][0] = 2; a.arr[1][3] = a.arr[1][5] = a.arr[2][3] = a.arr[2][5] = 4;
        a.arr[1][4] = a.arr[2][4] = 6;
        a.arr[3][3] = a.arr[4][4] = a.arr[5][5] = a.arr[6][6] = 1;
        a.arr[3][6] = a.arr[4][6] = a.arr[5][6] = 1;
        a.arr[3][4] = a.arr[3][5] = 3;
        a.arr[4][5] = 2;
        int T;
        scanf("%d",&T);
        ll N,aa,bb;
        while(T--){
            scanf("%I64d %I64d %I64d",&N,&aa,&bb);
            if(N==1)
                printf("%I64d
    ",aa);
            else if(N==2)
                printf("%I64d
    ",bb);
            else{
                matrix ans = quick_pow(a,N-2);
                ll ANS = 0;
                ANS = (ANS+ans.arr[1][0]*aa)%mod;
                ANS = (ANS+ans.arr[1][1]*bb)%mod;
                ANS = (ANS+ans.arr[1][2]*16)%mod;
                ANS = (ANS+ans.arr[1][3]*8)%mod;
                ANS = (ANS+ans.arr[1][4]*4)%mod;
                ANS = (ANS+ans.arr[1][5]*2)%mod;
                ANS = (ANS+ans.arr[1][6]*1)%mod;
                printf("%I64d
    ",ANS);
            }
        } 
        return 0;
    }
    View Code

    G.Do not pour out

    注:我不会在电脑写希腊字符,西塔会写成0-

    有直径2,高度2的圆柱体杯子,装d高度的水,把杯子倾倒至水正好不倒出,水面碰着杯沿,问此时水面面积

    d==0时S=0,样例给出

    d>=1时,水面椭圆是宽径为1,长径为2tan0-的椭圆,根据面积公式S=pi*length*width=pi/cos0-出解

    0<d<1时,水面被杯底截断,只能用积分做。

    把下述直线右边当做水的截面,一个个积分(岂可修!这么简单!为什么比赛时没想到呢!哎,都怪我被体积蒙蔽了)

    V=(0<=y<=2)S0dy

    S0=pi-a+k*1sina

    cosa=k/1

    k+1=ytan0-

    V=(0<=y<=2)S0dy

    =(0<=y<=2)∫pi-a+cosasinady

    =(pi<=y<=a1)1/tan0-*∫(pi-a+cosasina)(-sina)da

    a1=arccos(2tan0--1)

    手动转换和确定值间太费时了,还是二分把,反正数据量也不是很多,答案是S=s0/sin0-

    /*--------------------------------------------
     * File Name: HDU 5954
     * Author: Danliwoo
     * Mail: Danliwoo@outlook.com
     * Created Time: 2016-11-01 22:22:15
    --------------------------------------------*/
    
    #include <bits/stdc++.h>
    using namespace std;
    double Pi = acos(-1.0);
    double eps = 1e-100;
    double tran = 180/Pi;
    double vd;
    double V(double a) {
        return Pi*cos(a) - a*cos(a) + sin(a) - pow(sin(a), 3)/3;
    }
    double get(double theta) {
        double a1 = acos(2*tan(theta)-1);
        double v = (V(a1) - V(Pi))/tan(theta);
        return v;
    }
    bool eq(double x, double y) {
        return fabs(x-y) < eps;
    }
    double find(double l, double r) {
        int cnt = 200;
        if(eq(get(l), vd)) return l;
        while(cnt--) {
            double mid = (l+r) / 2;
            double gd = get(mid);
            if(eq(gd, vd)) return mid;
            if(gd > vd) r = mid;
            else l = mid;
        }
        return l;
    }
    int main() {
        int T;
        scanf("%d", &T);
        while(T--) {
            double d;
            scanf("%lf", &d);
            vd = d * Pi;
            if(eq(d, 0)) {
                printf("0.00000
    ");
                continue;
            }
            if(d - 1 > 0) {
                double theta = atan(2.0-d);
                double ans = Pi/cos(theta);
            //  printf("d>1 theta = %.5f
    ", theta*tran);
                printf("%.5f
    ", ans);
                continue;
            }
            double theta = find(eps, Pi/4);
            double a1 = acos(2 * tan(theta) - 1);
            double S1 = Pi - a1 + cos(a1) * sin(a1);
            double ans = S1 / sin(theta);
            printf("%.5f
    ", ans);
        }
        return 0;
    }
    View Code

    H.Guessing the Dice Roll

    n个人给出长度为l,互不相同的猜测序列,每次用色子<只有这6个元素:1,2,3,4,5,6>确定添加到旧序列末尾的元素,谁的序列与序列的后缀相同就赢,问每人的胜利概率

    直接就是AC自动机上。。。但是到了这一步就不知道如何转成矩阵来高斯消元

    后面才发现应该以主串(色子投出的序列)为分配概率的依据而不是以子串(猜测序列)为分配概率的依据

    这样就理解了为什么从根出发,概率是1/实边条数,不是1/实边权值和

    非根结点转移到下一层时,概率按照正常的1/6来计算,因为到了这步回溯也算在概率里

    非叶子结点(就是某人胜利的点)回溯到根的下一层时,要再乘从根出发到对应点的概率

    此外数组的第1维是目的点,第2位才是出发点,因为方程式的意义是从不同点一定概率到达本点的总和

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef double db;
    typedef long long ll;
    typedef unsigned int uint;
    typedef unsigned long long ull;
    const db eps=1e-6;
    const int N=110;
    const int M=100010;
    #define lson l, m, rt << 1
    #define rson m + 1, r, rt << 1 | 1
    #define CLR(a, b) memset(a, b, sizeof(a))
    
    struct trie {
        int sz,val[N],fail[N],tr[N][6];
        void init() {
            sz=0;
            memset(tr,0,sizeof(tr));
            memset(val,0,sizeof(val));
            memset(fail,0,sizeof(fail));
        }
        int trie_insert(int *ch) {
            int w=0;
            while (*ch!=-1&&tr[w][*ch]) w=tr[w][*ch],ch++;
            while (*ch!=-1) tr[w][*ch]=++sz,ch++,w=sz;
            val[w]=1;return w;
        }
        void trie_build() {
            queue<int>Q;
            for (int i=0;i<6;i++)
            if (tr[0][i]) Q.push(tr[0][i]);
            while (!Q.empty()) {
                int now=Q.front();Q.pop();
                if (val[now]) continue ;
                for (int i=0;i<6;i++)
                if (tr[now][i]) {
                    fail[tr[now][i]]=tr[fail[now]][i];
                    Q.push(tr[now][i]);
                } else tr[now][i]=tr[fail[now]][i];
            }
        }
    }AC;
    double p[N][N];
    int gauss(int n) {
        int i,j,k,mxi;
        db h;
        for (i=1;i<=n;i++) {
            mxi=i;
            for (j=i;j<=n;j++)
            if (fabs(p[j][i])>fabs(p[mxi][i])) mxi=j;
            if (fabs(p[mxi][i])<eps) return 0;
            if (mxi!=i) {
                for (j=i;j<=n+1;j++) swap(p[i][j],p[mxi][j]);
            }
            h=p[i][i];
            for (j=i;j<=n+1;j++) p[i][j]/=h;
            for (j=1;j<=n;j++)
            if (j!=i) {
                h=-p[j][i]/p[i][i];
                for (k=i;k<=n+1;k++) p[j][k]+=h*p[i][k];
            }
        }
        return 1;
    }
    int s[1000];
    int ans[1000];
    int main() {
        int t,n,l;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&n,&l);
            AC.init();
            for(int i=0;i<n;i++)
            {
                for(int j=0;j<l;j++)
                {
                    scanf("%d",s+j);s[j]--;
                }
                s[l]=-1;
                ans[i]=AC.trie_insert(s);
            }
            AC.trie_build();
            for(int i=0;i<=AC.sz;i++)
            {
                s[i]=0;
                for(int j=0;j<6;j++)if(AC.tr[i][j])s[i]++;
            }
            memset(p,0,sizeof(p));
            for(int i=1;i<=AC.sz;i++)p[i][i]=1.0;
            for(int i=0;i<6;i++)if(AC.tr[0][i])p[AC.tr[0][i]][AC.sz+1]+=1.0/s[0];//从根部出发,由于是按主串算的,要均分
            for(int i=1;i<=AC.sz;i++)
            {
                for(int j=0;j<6;j++)if(AC.tr[i][j])p[AC.tr[i][j]][i]-=1.0/6.0;
                if(s[i]!=6 && !AC.val[i])//i结点是非叶子且能回溯到边的
                {
                    for(int k=0;k<6;k++)
                    {
                        if(AC.tr[0][k])p[AC.tr[0][k]][i]-=1.0*(6-s[i])/6.0/s[0];
                    }
                }
            }
            gauss(AC.sz);
            for(int i=0;i<n;i++)printf("%.6f%c",p[ans[i]][AC.sz+1],i==n-1?'
    ':' ');
        }getchar();getchar();
        return 0;
    }
    View Code

     I.The Elder

    一棵树,从1点到其他点的传递方式有2种:通过其他中转站停留P时再出发,连续赶路,其中连续赶路dis的花费是dis^2,问从1点到其他点的最优距离最长的距离

    一开始想到直接树DP,但是还要在树上储存数据不好下手

    看了下大神博客才知道有斜率优化这东西

    dp[i]=min(dp[j]+(dis[i]-dis[j])^2)+P

    然后设j比k优,则

    dp[j]+(dis[i]-dis[j])^2+P <= dp[k]+(dis[i]-dis[k])^2+P

    得到[(dp[j]+dis[j]*dis[j])-(dp[k]+dis[k]*dis[k])] / 2(dis[j]-dis[k]) <=dis[i].

    所以我们可以看出以下两点:我们令g[k,j]=(yj-yk)/(xj-xk)

    第一:如果上面的不等式成立,那就说j比k优,而且随着i的增大上述不等式一定是成立的,也就是对i以后算DP值时,j都比k优。那么k就是可以淘汰的。

    第二:如果 k<j<i   而且 g[k,j]>g[j,i] 那么 j 是可以淘汰的。

    假设  g[j,i]<dis[i]就是i比j优,那么j没有存在的价值

    相反如果 g[j,i]>dis[i] 那么同样有 g[k,j]>sum[i]  那么 k比 j优 那么  j 是可以淘汰的

    然后就单调队列搞斜率dp

    至于树上的回溯导致的状态返回问题,把队尾附近的较优方案取出来标注时间戳还有在队位置,放到栈里,遍历子树时从栈放出来入队

    //kopyh
    #include <bits/stdc++.h>
    #define INF 0x3f3f3f3f
    #define MOD 1000000007
    //#define N 112345
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int N=100005;
    vector<pii> g[N];
    int m;
    ll dp[N],dist[N];
    int tim;
    int q[N],head,tail;
    struct tripl
    {
        int pos,val,timer;
        tripl(){}
        tripl(int pos,int val,int timer){this->pos=pos;this->val=val;this->timer=timer;}
    }tmp;
    stack<tripl> st;
    inline ll dy(int i)
    {
        return dp[i]+dist[i]*dist[i];
    }
    
    inline ll dx(int j,int k)
    {
        return 2*(dist[j]-dist[k]);
    }
    
    inline ll f(int j,int k)
    {
        return dy(j)-dy(k);
    }
    void dfs(int s,int fa)
    {
        int curr=tim++;
        while(head<tail && f(q[head+1],q[head])<=dist[s]*dx(q[head+1],q[head]))head++;
        dp[s]=dp[q[head]]+(dist[s]-dist[q[head]])*(dist[s]-dist[q[head]])+m;
        while(head<tail && f(s,q[tail])*dx(q[tail],q[tail-1])<=f(q[tail],q[tail-1])*dx(s,q[tail]))
        {
            st.push(tripl(tail,q[tail],curr));
            tail--;
        }
        q[++tail]=s;
        int th=head,tt=tail;
        for(int i=0;i<g[s].size();i++)
        {
            int to=g[s][i].first,val=g[s][i].second;
            if(fa==to)continue;
            dist[to]=dist[s]+val;
            head=th,tail=tt;
            while(!st.empty())
            {
                tmp=st.top();
                if(tmp.timer<=curr)break;
                q[tmp.pos]=tmp.val;
                st.pop();
            }
            dfs(to,s);
        }
    }
    
    int main()
    {
        int i,j,k,cas,T,t,x,y,z,n;
        scanf("%d",&T);
        cas=0;
        while(T--)
        {
            ll maxans=0;
            scanf("%d%d",&n,&m);
            for(i=1;i<=n;i++)g[i].clear();
            for(i=1;i<n;i++)
            {
                scanf("%d%d%d",&x,&y,&z);
                g[x].push_back(make_pair(y,z));
                g[y].push_back(make_pair(x,z));
            }
            while(!st.empty())st.pop();
            head=tim=0,tail=-1;
            dist[0]=dist[1]=0;
            dp[1]=-m;
            q[++tail]=1;
            int th=head,tt=tail;
            for(i=0;i<g[1].size();i++)
            {
                int to=g[1][i].first,val=g[1][i].second;
                dist[to]=dist[1]+val;
                head=th,tail=tt;
                while(!st.empty())
                {
                    tmp=st.top();
                    if(tmp.timer<=0)break;
                    q[tmp.pos]=tmp.val;
                    st.pop();
                }
                dfs(to,1);
            }
            for(i=1;i<=n;i++)maxans=max(maxans,dp[i]);
            printf("%I64d
    ",maxans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    找到排序矩阵中从小到大第K个数字
    使用VSCODE开发UE4
    UE4添加模块
    游戏串流
    DIY Arduino 方向盘
    免费/开源软件推荐
    把引擎插件变成工程插件
    MergeActors技巧
    烘焙卡在99%
    UMG里没有"Prefab"怎么办?
  • 原文地址:https://www.cnblogs.com/dgutfly/p/6041250.html
Copyright © 2011-2022 走看看