BestCoder Round #89

  过了这么久才来写……

  BC的后两道题好难……(第二道题也不怎么简单……)

1001 Fxx and string

  正着倒着枚举一次就ok

  

#include<iostream>
#include<cstdio>
#include<map>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
#define N 10005
char a[N];
int main() {
    int T,len,ans;
    scanf("%d",&T);
    while(T--) {
        scanf("%s",a+1);
        len = strlen(a+1);
        ans = 0;
        for(int i = 1;i <= len;i++){
            if(a[i] != 'y') continue;
            for(int k = 1;true;k++){
                if(i*k*k > len) break;
                if(a[i*k]=='r' && a[i*k*k]=='x') ans++;
            }
        }
        for(int i = 1;i <= len;i++){
            if(a[i] != 'x') continue;
            for(int k = 1;true;k++){
                if(i*k*k > len) break;
                if(a[i*k]=='r' && a[i*k*k]=='y') ans++;
            }
        }
        printf("%d
",ans);
    }
    return 0;
}
View Code

  这个题更新数据以后,爆搜肯定挂,比如(1000000,1,100000)

  所以要用dp,dp[x] = min(dp[x-i],dp[x/k]) ,1<=i<=t,容易想明白,但是暴力转移肯定挂,至于线段树,我帮你们写了,也挂……

  所以只能维护单调队列来优化这个dp

  维护[x-t,x-1]之间的单调队列,使其从队头到队尾是递增的,然后正常转移,更新单调队列就可以(单调队列在dp里的用处真的很大)

  单调队列代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<deque>
using namespace std;
const int INF = 1e9;
const int N = 1e6+6;
int dp[N],n,k,t;
deque<int> dq; ///维护一个从队尾到队头 递减的队列
int main() {
    int T,x;
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d%d",&n,&k,&t);
        dp[1]=0;
        while(!dq.empty()) dq.pop_back();
        dq.push_back(1);
        for(int i=2; i<=n; i++) {
            dp[i]=INF;
            if(i%k==0) dp[i]=min(dp[i],dp[i/k]+1);
            while(!dq.empty()) {
                x=dq.front();
                if(x<i-t||x>i-1) dq.pop_front();
                else break;
            }
            if(!dq.empty()) dp[i]=min(dp[i],dp[x]+1);
            while(!dq.empty()) {
                x=dq.back();
                if(dp[x]>=dp[i]) {
                    dq.pop_back();
                } else break;
            }
            dq.push_back(i);
        }
        printf("%d
",dp[n]);
    }
    return 0;
}
View Code

  挂了的线段树代码(笑哭)

#include<iostream>
#include<cstdio>
#include<map>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e6+5;
#define lc 2*node
#define rc 2*node+1
#define MAX 1e9
int seg[N*4+10],dp[N];
void Build(int node,int l,int r){
    if(l == r) seg[node] = MAX;
    else {
        int mid = (l+r)>>1;
        Build(lc,l,mid);
        Build(rc,mid+1,r);
        seg[node] = min(seg[lc],seg[rc]);
    }
}
void Update(int node,int l,int r,int k,int num){
    if(l==r) {
       seg[node] = num;
       return;
    }
    int mid = (l+r)>>1;
    if(k <= mid) Update(lc,l,mid,k,num);
    else Update(rc,mid+1,r,k,num);
    seg[node] = min(seg[lc],seg[rc]);
}
int query(int node,int l,int r,int ql,int qr){
    int p1,p2;
    if(ql > r || qr < l) return MAX;
    if(l >= ql && r <= qr) return seg[node];
    int mid = (l+r)>>1;
    p1 = query(lc,l,mid,ql,qr);
    p2 = query(rc,mid+1,r,ql,qr);
    return min(p1,p2);
}
int main()
{
    int T,x,k,t;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d%d",&x,&k,&t);
        Build(1,1,x);
        dp[1] = 0;
        Update(1,1,x,1,dp[1]);
        for(int i = 2;i <= x;i++){
            int q = query(1,1,x,i-t,i-1);
            dp[i] = q+1;
            if(i % k == 0) dp[i] = min(dp[i],dp[i/k]+1);
            Update(1,1,x,i,dp[i]);
        }
        printf("%d
",dp[x]);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/jifahu/p/6202361.html