2021“MINIEYE杯”中国大学生算法设计超级联赛(4)

hoj暑期第四场

1001

  • 题意

给你定义一个函数
math.svg
然后,\(S(x)=\sum_{j=1}^xf(j)\), 求 \(\lim \limits_{x\to \infty}S(x)=c\) , s(x)中x趋近正无穷的极限得是个常数

  • 思路

非常难受,就这种题,还有人能wa4,5发的啊。呜呜呜呜呜

code:

void solve(){
    string str;
    cin >> str;
    bool flag = 0;
    for(int i = 0;i < str.size();i ++) {
        if(isdigit(str[i]) && str[i] != '0') {
            flag = 1;
            break;
        }
    }
    if(!flag) cout << "YES" << endl;
    else cout << "NO" << endl;
}

1002

  • 题意

就是给你一颗树,每个节点都有一个颜色,定义\(a_i,_j\)表示从节点i到节点j颜色不同的数量,让你求
\(f(i,19560929)=\sum_{j=1}^n a_{i,j}x^{j-1}\)
这个公式中mod (\(10^9+7\)) 和 (\(10^9+9\))得出的不同值。

  • 思路

emmm,我就是用以每个点为根,扫了一边dfs后加个预处理就过了昂()

code:

const int N = 2010;
const double INF = 1e9;
const int M = 2 * N;
ll ans[N][2];
ll f[N][N];
ll sum1[N], sum2[N];
int h[N],e[M],ne[M],w[N],idx;
bool st[N];

void add(int a,int b) {
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
int root;
void dfs(int u,int fa,int val) {
    for(int i = h[u];~i;i = ne[i]) {
        int j = e[i];
        if(j == fa) continue;
        f[root][j] = val;
        bool flag = 0;
        if(!st[w[j]]) {
            st[w[j]] = 1;
            flag = 1;
            f[root][j] ++;
        }
        dfs(j,u,f[root][j]);
        if(flag) {
            st[w[j]] = 0;
        }
    }
}

void init() {
    ll x = 19560929;
    ll mod = 1e9 + 7;
    sum1[0] = 1;
    for(int i = 1;i <= 2000;i ++) {
        sum1[i] = sum1[i - 1] * x % mod;
    }
    mod = 1e9 + 9;
    sum2[0] = 1;
    for(int i = 1;i <= 2000;i ++) {
        sum2[i] = sum2[i - 1] * x % mod;
    }
    
}

void solve(){
    int n;
    scanf("%d", &n);
    idx = 0;
    memset(h,-1,sizeof h);
    for(int i = 2;i <= n;i ++) {
        int x;
        scanf("%d", &x);
        add(i,x), add(x,i);
    }
    for(int i = 1;i <= n;i ++) scanf("%d", &w[i]);
    for(int i = 1;i <= n;i ++) {
        root = i;
        f[i][i] = 1;
        st[w[i]] = 1;
        dfs(i,-1,1);
        st[w[i]] = 0;
    }
    for(int i = 1; i <= n;i++){
        ll sum = 0;
    	ll x = 19560929;
    	ll mod = 1e9 + 7;
    	for(int j = 1; j <= n; j++){
    		sum = (sum + f[i][j]%mod*sum1[j-1]%mod + mod)%mod;
		}
		sum %= mod;
		ans[i][0] = sum;
		 
		mod = 1e9 + 9;
		sum = 0;
    	for(int j = 1; j <= n; j++){
    		sum = (sum + f[i][j]*sum2[j-1]%mod + mod)%mod;
		}
		sum %= mod;
		ans[i][1] = sum; 
    }
    for(int i = 1; i <= n; i++){
        cout << ans[i][0] << " " << ans[i][1] << endl;
    }
}

1008

  • 题意

一个僵尸,在\(n * m\)的地图的地图中走,并且只能想下和向右走,并且其中有k个障碍物,问你僵尸从(1,1)开始能到的所有点的数量

数据范围:\(1<=t<=20\) , \(2<= n,m,k<= 10^5\)

  • 思路

考场上是按题解写的(用线段树维护上一层不能向下走的集合),没调出来,还是t了,当时是k\(log^2n写的\),后面看std,又是维护上一层可行(可以向下走)的区域,都差不多吧~, 按照std的思想又码了一遍,还是太菜了,这个query和update中按照情况,还是L,R进行变动这个没想出来啊,呜呜呜--

code:

const int N = 100100;
const double INF = 1e9;


ll sum[2][N << 2],laz[2][N << 2];

void build(int u,int l,int r) {
    sum[0][u] = sum[1][u] = 0;
    laz[0][u] = laz[1][u] = -1;
    if(l == r) {
        return;
    }
    int mid = l + r >> 1;
    build(u << 1, l, mid);
    build(u << 1 | 1, mid + 1,r);
}
 
void down(int u,int l,int r, int k){
    if(laz[k][u] == -1) return;
    int mid = l + r >> 1;
    
    ll la = laz[k][u];
    sum[k][u << 1] = la * (mid - l + 1);
    sum[k][u << 1 | 1] = la * (r - mid);
    
    laz[k][u << 1] = la;
    laz[k][u << 1 | 1] = la;
    
    laz[k][u] = -1;
}

void update(int L,int R,ll v,int u,int l,int r,int k){
    if(l >= L && r <= R){
        sum[k][u] = v * (r - l + 1);
        laz[k][u] = v;
        return;
    }
    down(u,l,r,k);
    int mid = l + r >> 1;
    if(R <= mid) update(L, R, v, u << 1, l, mid,k);
    else if(L > mid) update(L, R, v, u << 1 | 1,mid + 1, r,k);
    else {
        update(L,mid,v,u << 1,l,mid,k);
        update(mid + 1,R,v,u << 1 | 1,mid + 1,r,k);
    }
    sum[k][u] = (sum[k][u << 1] + sum[k][u << 1 | 1]);
}

ll query(int L,int R,int u,int l,int r,int k){
    if(!sum[k][u]) return INF;
    if(l == r) return l;
    down(u,l,r,k);
    int mid = l + r >> 1;
    if(l >= L && r <= R){
        if(sum[k][u << 1] > 0) return query(l,mid,u << 1,l, mid,k);
        else return query(mid + 1, r, u << 1 | 1, mid + 1, r,k);
    }
    if(R <= mid) return query(L,R,u << 1,l,mid,k);
    else if(L > mid) return query(L,R,u << 1 | 1, mid + 1, r,k);
    else return min(query(L,mid,u << 1,l,mid,k), query(mid + 1,R,u << 1 | 1, mid + 1, r,k));
}


vi p[N];

void solve(){
    int n,m,k;
    cin >> n >> m >> k;
    for(int i = 1;i <= k;i ++) {
        int a,b;
        cin >> a >> b;
        p[a].pb(b);
    }
    ll ans = 0;
    build(1,1,m);
    update(1,m,1,1,1,m,1); // 起点是可以的
    if(p[1].size()) {
        sort(p[1].begin(), p[1].end());
        update(p[1][0], m,0,1,1,m,1);
    }
    ans += sum[1][1];
    // 通过上一行的可行区域计算下一行的可行区域
    for(int i = 2;i <= n;i ++) {
        int l = 0;
        sort(p[i].begin(), p[i].end());
        for(int it : p[i]) {
            if(it > l + 1) {
                int pos = query(l + 1, it - 1, 1, 1, m,(i & 1) ^ 1); // 找上一层在l + 1 ~ it - 1之中,可行的最靠左的点
                if(pos != INF) update(pos, it - 1, 1, 1, 1, m ,i & 1); // 那么左端点到it - 1都是可到达的区域
            }
            l = it;
        }
        if(l + 1 <= m) {
            int pos = query(l + 1,m,1,1,m,(i & 1) ^ 1); // 同上
            if(pos != INF) update(pos,m,1,1,1,m,i & 1);
        }
        ans += sum[i & 1][1];
        update(1,m,0,1,1,m,(i & 1) ^ 1); // 清空,为下一层做准备
    }
    cout << ans << endl;
    for(int i = 1;i <= n;i ++) p[i].clear();
}

1009

  • 题意

给你30行字符串,每行100列,并且是个车牌,后5位字母或数组,第2位字母,第1位汉字。

  • 思路

for两层,第一层从后往前,记录答案,最后第7个的时候不用记录,让l,r在那,然后输出即可也就汉字能让我wa一发了0.0

code:

string str[31];

vector<pii> ans;
int now;
void solve(){
    for(int i = 0;i < 30;i ++) {
        cin >> str[i];
    }
    
    cout << "Case #" << (++ now) << ":" << endl;
    int l = 0,r = 0;
    for(int i = str[0].size() - 1;i >= 0;i --) {
        bool flag = 0;
        for(int j = 0;j < 30;j ++) {
            if(str[j][i] != '.') {
                flag = 1;
                break;
            }
        }
        if(flag && !l) l = i + 1;
        else if(flag) r = i + 1;
        
        if(!flag && l && r && ans.size() < 6) {
            ans.push_back({r,l});
            l = 0,r = 0;
        }
    }
    cout << r << ' ' << l << endl;
    for(int i = 5;i >= 0;i --) {
        cout << ans[i].first << ' ' << ans[i].second << endl;
    }
    ans.clear();
}
posted @ 2021-07-29 21:04  darker_wxl  阅读(65)  评论(0编辑  收藏  举报
window.onload = function(){ $("#live2dcanvas").attr("style","position: fixed; opacity: 0.7; left: 70px; bottom: 0px; z-index: 1; pointer-events: none;") }