Educational Codeforces Round 13

D. Iterated Linear Function

  线性递推。按照我以前的做法,就是矩阵快速幂了。后来我发现,其实这题可以不需要矩阵。递推一下找找规律 x2=ax1+b x3=aax1+ab+b x4=aaax1+aab+ab+b …我们可以发现, xn 可以看成由两部分组成,前面是 a 的幂乘以x1,后面部分是等比数列的和。然后根据等比数列求和公式+快速幂+费马小定理(解决取模除法)就好了。
  其实还有更简单的方法,就是把快速幂里面的乘法运算,换成” a+b ”就好了。

#include <bits/stdc++.h>

using namespace std;

#define ll long long

const ll mod = 1e9+7;  

ll a,b,x,n;

void fp(){
    ll res = x;
    while(n){
        if(n&1){
            res = res * a + b;
            res %= mod;
        }
        b = b * a + b;
        b %= mod;
        a *= a;
        a %= mod;
        n>>=1;
    }
    cout<<res<<endl;
}  

int main(){
    cin>>a>>b>>n>>x;
    fp();
    return 0;
} 

E. Another Sith Tournament

  显然是状压dp。但是比赛的时候我居然没有做出来。。状态应该是这样的, dp(i,j) 表示还有集合 i 的人还需要比,下场j一定要出战,这样的情况下,玩家1的胜率。初始状态是 dp(1,1)=1 ,其他为0,也就是只剩下玩家1时,他必胜。敲的时候老想着比完的人的集合,其实用还需要比的人的集合倒推会更科学。

#include <bits/stdc++.h>


using namespace std;

#define ll long long


double p[22][22];

double dp[1<<18][18];


int bit[1<<18];

//可以递推去计算,每个O(1) 
int bit_cnt(int x){
    int res = 0;
    while(x){
        if(x&1){
            res++;
        }
        x>>=1;
    }
    return res;
}

int who(int x){
    int res = 0;
    while(x){
        res++;
        if(x&1){
            return res;
        }
        x>>=1;
    }
    return 0;
}

vector<int> whos(int x){
    vector<int> res;
    int cur = 0;
    while(x){
        cur++;
        if(x&1){
            res.push_back(cur);
        }
        x>>=1;
    }
    return res;
}

bool cmp(int a,int b){
    return bit_cnt(a)<bit_cnt(b);
}

int main(){
    int n;
    cin>>n;

    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cin>>p[i][j];
        }
    }

    int End = 1<<n;
    for(int i=1;i<End;i++){
        bit[i] = i;
    }
    sort(bit+1,bit+End,cmp);

    dp[1][1] = 1;

    for(int i=1;i<End;i++){
        int b = bit[i];
        if((b&1)==0){
            continue;
        }
        vector<int> person = whos(b);
        int sz = person.size();
        for(int j = 0;j<sz;j++){
            for(int k=0;k<sz;k++){
                if(j==k)continue;
                dp[b][person[j]] = max(dp[b][person[j]],dp[b^(1<<(person[j]-1))][person[k]] * p[person[k]][person[j]] + 
                    dp[b^(1<<(person[k]-1))][person[j]] * p[person[j]][person[k]]);
            }
        }
    }

    double ans = 0;
    for(int i=1;i<=n;i++){
        ans = max(ans,dp[End-1][i]);
    }

    printf("%.10f\n",ans);

    return 0;
} 

F. Lena and Queries

  首先,最优解的点,肯定出现在上凸壳。但是凸壳是动态的,会增加和删除点,所以我们不能过于频繁去求凸壳,于是分块。对于每块,对之前出现且没被删除的点构造凸壳,排序块内询问,利用单调性在 O(n) 内得解,块内直接暴力。注意实现的时候常数尽量小一点。。。
  另外这个题可以用传说中的cdq分治,改天学习一下。

#include <bits/stdc++.h>

using namespace std;

#define ll long long

const int maxn = 300010;
const ll INF = 2e18;

int t[maxn];
ll a[maxn];
ll b[maxn];
bool ban[maxn];
ll ans[maxn];
ll ans2[maxn];

struct Point{
    ll x,y;
    Point(ll x,ll y):x(x),y(y){
    }
    Point(){
    }

    bool operator<(const Point &other)const{
        if(x!=other.x){
            return x<other.x;
        }
        return y>other.y;
    }
};

Point ch[maxn];
pair<Point,int> ppi[maxn];

int sz;

int n;
int k;

void ConvexHull(int end){
    sz = 0;
    Point pre = Point(-INF,-INF);
    for(int i=0;i<k;i++){
        Point pt = ppi[i].first; 
        if(ban[ppi[i].second] || ppi[i].second>end ){
            continue;
        }
        if(pt.x == pre.x){
            continue;
        }
        pre = pt;
        if(sz<2){
            ch[sz++] = pt;
        }else{
            while(sz>=2 && (pt.y-ch[sz-1].y)*(ch[sz-1].x-ch[sz-2].x) >= 
                    (ch[sz-1].y-ch[sz-2].y)*(pt.x-ch[sz-1].x) ){
                sz--;
            }
            ch[sz++] = pt;
        }
    }
}

int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%d",&t[i]);
        if(t[i] == 1){
            scanf("%I64d%I64d",&a[i],&b[i]);
            ppi[k++] = make_pair(Point(a[i],b[i]),i);
        }else{
            scanf("%I64d",&a[i]);
        }
        ans[i] = ans2[i] = -INF;
    }

    sort(ppi,ppi+k);

    int LEN = sqrt(n);
    Point pt_in_block[555];
    pair<ll,int> query_in_block[555];
    int cntq = 0;
    int k = 0;
    for(int s=1;s<=n;s+=LEN){
        int e = min(n+1,s+LEN);
        cntq = 0;
        for(int i=s;i<e;i++){
            if(t[i] == 3){
                for(int j=s;j<e;j++){
                    if(t[j] == 1 && j < i && !ban[j]){
                        ans[i] = max(ans[i],b[j]+a[j]*a[i]);
                    }else if(t[j] == 2 && j > i && a[j] < i){
                        int aa = a[a[j]];
                        int bb = b[a[j]];
                        ans[i] = max(ans[i],bb+aa*a[i]);
                    }
                }
                query_in_block[cntq++] = make_pair(a[i],i);
            }else if(t[i] == 2){
                ban[a[i]] = 1;
            }
        }

        sort(query_in_block,query_in_block+cntq);
        ConvexHull(s-1);
        if(sz != 0){
            int pos = 0;
            for(int i=0;i<cntq;i++){
                while(pos<sz){
                    ll val = ch[pos].y + query_in_block[i].first*ch[pos].x;
                    if( val > ans2[query_in_block[i].second]){
                        ans2[query_in_block[i].second] = val;
                    }else{
                        if(pos){
                            pos--;
                        }
                        break;
                    }

                    pos++;
                    if(pos==sz){
                        if(pos)pos--;
                        break;
                    }
                }
            }
        }
    }

    for(int i=1;i<=n;i++){
        if(t[i] == 3){
            ll a = max(ans[i],ans2[i]);
            if(a == -INF){
                printf("EMPTY SET\n");
            }else{
                printf("%I64d\n",a);
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值