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