1. 程式人生 > >XTU Monthly, April 2014

XTU Monthly, April 2014

題意:0通過+1,-1,*2操作得到n(10^18)的最小方案數

思路:倒著看,偶數必然由*2得到,奇數由+1或-1得到,開個map存一下算過的

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
using namespace std;
typedef long long LL;
map<LL,int>mp;
LL solve(LL n){
    if(mp[n]!=0) return mp[n];
    if(n==0) return mp[n]=0;
    else if(n==1) return mp[n]=1;
    if(n&1) return mp[n]=min(solve(n+1),solve(n-1))+1;
    else return mp[n]=solve(n/2)+1;
}
int main(){
    LL n;
    mp.clear();
    while(scanf("%I64d",&n)!=EOF){
        printf("%I64d\n",solve(n));
    }
    return 0;
}

B.Lucky Wheel

題意:轉盤1/2的概率無獎,1/8一等獎,1/8二等獎,1/8三等獎,1/8優秀獎,求x次一等獎,y次二等獎的期望

思路:用dp[i][j]表示i次一等獎,j次二等獎的期望

dp[i][j] = 1 + dp[i][j]  * 3/4 + dp[i-1][j] * 1/8 + dp[i][j-1] * 1/8

dp[i][j] = 4 + (dp[i-1][j] + dp[i][j-1]) * 1/2

暴力處理一下就出來了

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
using namespace std;
typedef long long LL;
#define maxn 1010
double dp[maxn][maxn];
int main(){
    for(int i=0;i<maxn;i++)
        dp[0][i]=8*i,dp[i][0]=8*i;
    for(int i=1;i<maxn;i++){
        for(int j=1;j<maxn;j++)
            dp[i][j]=4.0+(dp[i-1][j]+dp[i][j-1])/2.0;
    }
    int x,y;
    while(scanf("%d%d",&x,&y)!=EOF){
        printf("%.6lf\n",dp[x][y]);
    }
    return 0;
}

C.A+B

題意:求只包含a,b數字的序列和為n的方案數

思路:擴充套件歐幾里得求出最小解的情況x0,y0,在保證都大於等於零的情況下,可以變換lcm(a,b)(即x0+=lcm(a,b)/b,y0-=lcm(a,b)/a)

所以總的方案數為 y0*b/lcm(a,b)+1 .     a=b的時候特判

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
using namespace std;
typedef long long LL;
LL exgcd(LL a,LL b,LL &x,LL &y){
    if(b==0){
        x=1,y=0;
        return a;
    }
    else{
        LL ans=exgcd(b,a%b,x,y);
        LL tmp=x;
        x=y;
        y=tmp-a/b*y;
        return ans;
    }
}
LL gcd(LL a,LL b){
    if(b==0) return a; return gcd(b,a%b);
}
LL lcm(LL a,LL b){
    return a/gcd(a,b)*b;
}
int main(){
    LL a,b,x,y,c;
    while(scanf("%I64d%I64d%I64d",&a,&b,&c)!=EOF){
        LL g=gcd(a,b);
        if(c%g!=0){
            printf("0\n");
            continue;
        }
        else if(a==b){
            printf("%d\n",(c%a)==0 );
        }
        else{
            a/=g,b/=g,c/=g;
            exgcd(a,b,x,y);
            x*=c; x=(x%b+b)%b;
            a*=g,b*=g,c*=g;
            LL x0=x,y0=(c-a*x)/b;
            if(y0<0){
                printf("0\n");
                continue;
            }
            LL l=lcm(a,b);
            printf("%I64d\n",b*y0/l+1);
        }
    }
    return 0;
}

D.Hexa Kill

題意:給出n個物品,m種限制,以及n個物品分別第幾個被選所消耗的能量,以及m對限制(x,y)表示x在y之後被選,求最小消耗

思路:喵似是圖論,不會

題意:有根樹每個節點有個權值,一開始都是0。 你有這麼兩種操作。
操作1: 你可以使某個節點加上一個值v(1≤v≤100),那麼這個節點的兒子就會加上2v,它兒子的兒子就加上3v...
操作2: 詢問一個節點的權值。

思路:線段樹。更新一個深度為d節點,它的兒子深度為dn,節點值為x+(dn-d+1)*v=x+dn*v-d*v+v,d*v是常數 ( by 小建建)

// by qqspeed
#include <stdio.h>
#include <string.h>
#include <vector>
#include <algorithm>
using namespace std;
#pragma comment(linker,"/STACK:102400000,102400000")

inline int input(){
    int ret=0;bool isN=0;char c=getchar();
    while(c<'0' || c>'9'){
        if(c=='-') isN=1;
        c=getchar();
    }
    while(c>='0' && c<='9'){
        ret=ret*10+c-'0';
        c=getchar();
    }
    return isN?-ret:ret;
}

typedef long long ll;
#define N 100005
#define L t<<1
#define R t<<1|1

int t,n;
vector<int>e[N];
int op,x,y,q;
int cnt;
int to[N],rTo[N],r,dis[N],last[N];

inline void dfs(int now,int pre){
    dis[now] = dis[pre]+1;
    to[now]=cnt;
    rTo[cnt]=now;
    cnt++;
    for(int i=0;i<e[now].size();i++){
        dfs(e[now][i],now);
    }
    last[now]=cnt-1;
}

struct node{
    int l,r;
    ll v1,v2;
    void init(int _l,int _r,ll _v1,ll _v2){
        l=_l,r=_r;
        v1=_v1,v2=_v2;
    }
}root[N<<2];

inline void push_down(int t){
    root[L].v1+=root[t].v1;
    root[R].v1+=root[t].v1;
    root[L].v2+=root[t].v2;
    root[R].v2+=root[t].v2;
    root[t].v1=root[t].v2=0;
}
inline void build(int t,int x,int y){
    root[t].init(x,y,0,0);
    if(x!=y){
        int mid=(x+y)>>1;
        build(L,x,mid),build(R,mid+1,y);
    }
}
inline void Add(int t,int x,int y,ll v1,ll v2){
    int l=root[t].l,r=root[t].r;
    if(l==x && r==y){
        root[t].v1+=v1;
        root[t].v2+=v2;
        return;
    }
    push_down(t);
    int mid=(l+r)>>1;
    if(y<=mid) Add(L,x,y,v1,v2);
    else if(x>mid) Add(R,x,y,v1,v2);
    else{
        Add(L,x,mid,v1,v2);
        Add(R,mid+1,y,v1,v2);
    }
}
inline ll query(int t,int x){
    int l=root[t].l,r=root[t].r;
    if(l==r){
        return root[t].v2+root[t].v1*dis[rTo[l]];
    }
    push_down(t);
    int mid=(l+r)>>1;
    if(x<=mid) return query(L,x);
    else return query(R,x);
}
int main(){
    t=input();
    while(t--){
        n=input();
        for(int i=0;i<=n;i++) e[i].clear();
        cnt=1;
        for(int i=1;i<=n;i++){
            x=input();
            if(x==0) r=i;
            else e[x].push_back(i);
        }
        dis[0]=0;
        dfs(r,0);
        build(1,1,cnt);
        q=input();
        while(q--){
            op=input();
            if(op==2){
                x=input();
                printf("%I64d\n",query(1,to[x]));
            }
            else{
                x=input();
                y=input();
                ll v1=y;
                ll v2=(1-dis[x])*y;
                y=last[x];
                x=to[x];
                Add(1,x,y,v1,v2);
            }
        }
    }
    return 0;
}