Educational Codeforces Round 121 (Rated for Div. 2) // 代码记录,无题解

A题

A:题目要每对直接的距离相同,那么把每对相邻,那么每对距离一定相同,所以直接对题目给的字符串进行排序输出即可,,排序、构造

#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <string>
 
using namespace std;
 
int main(){
    ios::sync_with_stdio(false) ;
 
    int n ;
    cin >> n ;
 
    while (n--){
        string x ;
        cin >> x ;
 
        sort(x.begin(),x.end()) ;  // 排序输出
 
        cout << x << "\n" ; 
    }
    
    return 0;
}

B题

B:按照题目中的模拟, 模拟

#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <string>
 
using namespace std;
 
int main(){
    ios::sync_with_stdio(false) ;
    cin.tie(0) ;
    cout.tie(0) ;
 
    int t ;
    cin >> t ;
    while(t --){
        string x ;
        cin >> x;
 
        int mx = 0;  // mx指将mx和mx+1下标合并,可以得到最大值,先设置为0
        for(int i = 1;  i + 1 < x.size() ; i ++){
            int a = x[mx] - '0' + x[mx + 1] - '0' ;
            int b = x[i] - '0' + x[i+1] - '0' ;
 
            if(a >= 10 && b < 10 || (a < 10 && b < 10)) ;  // 当这两个种情况不需要更新最大值
            else mx = i ;
        }
 
        string ans ;
 
        for(int i = 0 ; i < x.size() ; i++){
            if(i == mx){
                int a = x[mx] - '0' + x[mx + 1] - '0' ;
                
                if(a >= 10){
                    ans.push_back('1') ;
                    a %= 10 ;
                }
 
                ans.push_back(a + '0') ;
 
                i ++ ;
            }jik1
            else ans.push_back(x[i]) ;
        }
 
        int k = 0 ;  // 输出最大值即可
        while(k + 1 < ans.size() && ans[k] == '0') k ++ ;
 
        for(int i = k ; i < ans.size() ; i ++) cout << ans[i] ;
        cout << '\n' ;
    }
    
    return 0;
}

c 题

贪心

#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
 
using namespace std;
 
typedef long long ll;
const int N = 110 ;
 
int n ;
ll k[N],h[N] ;
 
int main(){
    int t ;
    scanf("%d",&t) ;
 
    while(t--){
        scanf("%d",&n) ;
 
        for(int i = 1;  i <= n ; i ++) scanf("%lld",&k[i]) ;
 
        for(int i = 1;  i <= n ; i ++) scanf("%lld",&h[i]) ;
        
        ll pre = 0,mx = -1;
        ll ans = 0 ;
        for(int i = n ; i >= 1 ; i--){  // 从后往前循环
            ll t = max(pre,h[i]) ;  // 这时候的高度应该取当前需要的高度和上一个需要高度的最大值
            mx = max(mx,k[i]) ;  //代表这一段的最右端点
 
            if(k[i] - k[i-1] >= t){  // 如果这段距离满足t的高度,那么对i-1没有限制了
                ll w = mx - k[i] + t ;  // 那么这个是施法的长度,就是最右端点减去当前端点加上t
                ans += w * ( w + 1) / 2 ;  // 记录答案
                mx = -1 ;  // 初始化
                pre = 0 ;
            }
            else pre = t - (k[i] - k[i-1]) ; // 记录i-1应该达到的最小高度 ,, 贪心
        }
 
        printf("%lld\n",ans) ;
    }
    return 0;
}

D 题

枚举,二分

#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <vector>
 
using namespace std;
 
const int N = 2e5 + 100 ;
 
int n,m ;
int a[N] ;
int cnt[N] ;
vector<int> nums ;
 
int er[N] ;
 
void init(){
    for(int i = 0 ;i <= 18 ; i ++ ) er[i] = 1 << i ;
}
 
int get(int x){
    return lower_bound(nums.begin(),nums.end(),x) - nums.begin() ;
}
 
int main(){
    init() ;
    int t; 
    scanf("%d",&t) ;
 
    while(t--){
        scanf("%d",&n) ;
 
        nums.clear() ;
        for(int i = 1 ; i <= n ; i++) scanf("%d",&a[i]) ,nums.push_back(a[i]) ;
 
        sort(nums.begin(),nums.end()) ;   // 离散化
        nums.erase(unique(nums.begin(),nums.end()),nums.end()) ;
 
        for(int i = 1; i <= n ; i ++) cnt[get(a[i])] ++ ;  
 
        m = nums.size() ;
        
        int ans = 1e9 ;
        for(int i = 0 ; i <= 18 ; i ++){  // 枚举第一段
            for(int j = 0 ; j <= 18 ; j ++){  // 枚举第二段
                int res = 0 ,tot = 0,z = n ;
                int k = 0;
 
                while(k < m && tot + cnt[k] <= er[i]) tot += cnt[k ++] ;
                res += er[i] - tot ;
                z -= tot ;
 
                tot = 0 ;
                while(k < m && tot + cnt[k] <= er[j]) tot += cnt[k ++] ;
                
                res += er[j] - tot ;
                z -= tot ;
 
                res += er[lower_bound(er,er+19,z) - er] - z ;  // 二分第三段
 
                ans = min(ans,res) ;
            }
        }
 
 
        for(int i = 0 ; i < m ; i++) cnt[i] = 0 ;
 
        printf("%d\n",ans) ;
    }
    return 0;
}

E题

参考 小岛美奈子

图的遍历,发现性质如何才能移动

#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>

using namespace std;

const int N = 3e6 + 100 , M = 2* N ; 

int n,m,sum ; 
int h[N],e[M],w[M],ne[M],idx ;   // w为1代表新图中这条路可以走
int cnt[N] ;
bool col[N],st[N] ;


void add(int a,int b){
    e[idx] = b,ne[idx] = h[a],h[a] = idx ++ ;
}

void dfs1(int u,int fa){
    if(col[u]) cnt[u] = 1; 

    for(int i = h[u] ; ~ i ; i = ne[i]){
        int j = e[i] ;
        if(j == fa) continue ;
        dfs1(j,u) ;
        cnt[u] += cnt[j] ;

        if(cnt[j] >= 2 ) w[i^1] = 1;  //这里是可以下去找黑点,那么反过来,就是可以从下面上来
        if(sum - cnt[j] >= 2) w[i] = 1;  // 同理

        if(col[j] || col[u]) w[i] = w[i^1] = 1 ;  // 黑点周围的 
    }
}


void dfs2(int u){
    st[u] = 1,col[u] = 1;

    for(int i = h[u] ; ~ i ; i = ne[i]){
        int j = e[i] ;

        if(!st[j] && w[i]){
            dfs2(j) ;
        }
    }
}

int main(){
    ios::sync_with_stdio(false) ;
    cin.tie(0) ;
    cout.tie(0) ;

    cin >> n ;    
    m = n - 1 ;

    memset(h,-1,sizeof h) ;

    for(int i = 1;  i <= n ; i ++) cin >> col[i] ;

    for(int i = 1;  i <= n ; i++) if(col[i]) sum ++ ;

    for(int i = 0 ; i < m ; i ++){
        int a,b;
        cin >> a >> b; 
        add(a,b),add(b,a) ;
    }

    dfs1(1,-1) ;
    for(int i = 1 ; i <= n ; i++)  
        if(col[i] && !st[i])
            dfs2(i) ;


    for(int i = 1;  i <= n ; i ++) cout << col[i] << " " ;
    cout << '\n' ;
    return 0;
}

F题

参考rainboy

dp,排列组合

#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>

using namespace std;

typedef long long ll ;

const ll N = 1e7 + 100 ,mod = 998244353 ;
const ll L = 720720 ;

ll n,x,y,k,M ;
ll aa[N] ;
ll f[N] ;

int main(){
    cin >> n >> aa[0] >> x >> y >> k >> M ;

    
    for(int i = 1 ; i < n ; i++) aa[i] = (aa[i-1] *  x + y) % M ;

    ll p = 1 ;
    for(int i = k ; i >= 1;  i --){
        for(int j = L; j >= 0 ;  j --) f[j] = (f[j] * (n - 1) % mod + j * p % mod + f[j - j % i]) % mod ;  // 这是从后面操作像前面递推

        if(i > 1) p = p * n % mod ;
    }

    ll ans = 0 ;
    for(int i = 0 ; i < n ; i ++){
        ans = (ans + k * p % mod * (aa[i] - aa[i] % L) % mod + f[aa[i] % L]) % mod ;  // 这里k代表k个位置每个位置贡献,所以k * n^(k-1)就是i这个数的所有固定贡献,再加上i这个数的模数贡献
    }

    cout << ans << "\n" ;
    return 0 ;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值