其他分享
首页 > 其他分享> > Codeforces Round #816 (Div. 2) A-C

Codeforces Round #816 (Div. 2) A-C

作者:互联网

C题想了一种线段树,然后统计所有左右端点的麻烦做法,

 

A 题:思维

将长的边作为横坐标,短的边作为纵坐标,从左走到右即可。

注意当一条边横跨中间的那条线之后,另一条边只用多走一步就可以到达另一条路

//-------------------------代码----------------------------

//#define int ll
const int N = 1e5+10;
int n,m;

void solve()
{
    cin>>n>>m;
    if(n > m)  swap(n,m);
    if(m == 1 ) {
    cout<<0<<endl;rt;}
    cout<< (n - 1) * 2 + 1 + (m - 1) <<endl;
}
void main_init() {}
signed main(){
    AC();clapping();TLE;
    cout<<fixed<<setprecision(12);
    main_init();
//  while(cin>>n,n)
//  while(cin>>n>>m,n,m)
    int t;cin>>t;while(t -- )
    solve();
//    {solve(); }
    return 0;
}

/*样例区


*/

//------------------------------------------------------------

B题 模拟+构造

题意:n个数,每个数,除k向下取整并累加的和 等于 b ,和等于 s

构造这 n 个数

这n 个数的和最小 等于 k * b 

最大等于 k * (b + 1) - 1

然后保持 s 为后 n - i 个数的和 挨个输出就可以了

 

//-------------------------代码----------------------------

#define int ll
const int N = 1e5+10;
int n,m,k,b,s;

void solve()
{
    cin>>n>>k>>b>>s;
    int mx = max(1ll * 0,k * (b+1) - 1);
    int mn = k * b;
    if(mx + (n-1) * (k-1) < s || mn > s) {
//        dbb(mx + (n-1) * (k-1),s)
//        dbb(mn,s);
        cout<<-1<<endl;
        rt; 
    }
    int cnt = n;
    if(mx >= s) {
        cout<<s<<' '; n -- ;
        while(n -- ) cout<<0<<' ';
    } else {
        cout<<mx<<' ';
        s -= mx;
        cnt -- ;
        while(s) {
            cnt -- ;
            if(s > k - 1) {
                cout<<k - 1<<' ';s -= k - 1;
            } else {
                cout<<s<<' ';s -= s;
            }
        }
        while(cnt) {
            cout<<0<<' ';
            cnt -- ;
        }
    }
    cout<<endl;
}
void main_init() {}
signed main(){
    AC();clapping();TLE;
    cout<<fixed<<setprecision(12);
    main_init();
//  while(cin>>n,n)
//  while(cin>>n>>m,n,m)
    int t;cin>>t;while(t -- )
    solve();
//    {solve(); }
    return 0;
}

/*样例区


*/

//------------------------------------------------------------

C题:思维 贡献题   关键:维护连续相等的数的第一个点的贡献

求所有左边界和右边界,对于每个l 和 r 它的不同的数的种类的总和

对每个位置的数,计算它的贡献

枚举到 i ,左边界可以是[1,i] 右边界可以是 [i,n]

一:如果当前数 和左边不相等,贡献就是 i * (n - i + 1)

二:如果当前数 和左边相等,分几种情况

1. 将右边界定为 i

第一种 左边界 在连续相等的数之外,这个时候 这个数就没有贡献

第二种 左边界 在连续相等的 数之内,那它们的 位置到这个位置 都只有左边第一个数的贡献,后面的数包括这个数没有贡献

第三种 左边界 是 i ,因为是第一个数,所以有贡献。

2. 右边界定为 [i+1,n]

如果前面有相等 的数,左边界只有等于 i 的时候这个数才有一个贡献,

如果没有相等的数,就是第一种情况 

考虑右边有相等的数,因为这个数是第一个数,所以有一个贡献。

最后推出来 贡献是 (n - i + 1)

所以总共的贡献是 i * (n - i + 1) - (i - 1) * (n - i + 1) 

[1,i],[i,n] - [1,i-1],[i,n] = [i],[i,n] 

 

题目要求 维护单点修改后 的总贡献

考虑左右两边。

对于左边,如果改之前是连续相等,或者不相等,改之后也是一样,那相当于没改

  一:如果改之前是连续相等,改之后不相等,这个点 原来的贡献是 [i],[i,n] 现在是[1,i],[i,n] 

这个点的贡献就要加上 [1,i-1],[i,n] 的贡献,也就是 + (i-1) * (n-i+1) 

  二:如果改之前不想当,改之后相等,这个点 原来的贡献是 [1,i],[i,n] 现在是 [i],[i,n] 

这个点的贡献要减去 [1,i-1],[i,n] 的贡献, 就是 - (i-1)*(n-i+1) 

//-------------------------代码----------------------------

#define int ll
const int N = 1e5+10;
int n,m,k,b,s;

void solve()
{
    cin>>n>>k>>b>>s;
    int mx = max(1ll * 0,k * (b+1) - 1);
    int mn = k * b;
    if(mx + (n-1) * (k-1) < s || mn > s) {
//        dbb(mx + (n-1) * (k-1),s)
//        dbb(mn,s);
        cout<<-1<<endl;
        rt; 
    }
    int cnt = n;
    if(mx >= s) {
        cout<<s<<' '; n -- ;
        while(n -- ) cout<<0<<' ';
    } else {
        cout<<mx<<' ';
        s -= mx;
        cnt -- ;
        while(s) {
            cnt -- ;
            if(s > k - 1) {
                cout<<k - 1<<' ';s -= k - 1;
            } else {
                cout<<s<<' ';s -= s;
            }
        }
        while(cnt) {
            cout<<0<<' ';
            cnt -- ;
        }
    }
    cout<<endl;
}
void main_init() {}
signed main(){
    AC();clapping();TLE;
    cout<<fixed<<setprecision(12);
    main_init();
//  while(cin>>n,n)
//  while(cin>>n>>m,n,m)
    int t;cin>>t;while(t -- )
    solve();
//    {solve(); }
    return 0;
}

/*样例区


*/

//------------------------------------------------------------

 

标签:相等,cout,int,cin,Codeforces,solve,Div,贡献,816
来源: https://www.cnblogs.com/er007/p/16621177.html