Codeforces Round #804 (Div. 2) && Codeforces Round #802 (Div. 2) A~D
802
A
#include <bits/stdc++.h>
using namespace std;
const int N = 5e3+10;
const int M = 1<<16;
const int mod = 1e9+7;
#define int long long
#define LL long long
#define endl '\n'
#define Endl '\n'
#define yes cout<<"YES"<<endl;
#define no cout<<"NO"<<endl;
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
signed main(){
fast
int T;cin>>T;
while(T--){
int n,m;cin>>n>>m;
int sum=0;
for(int i=1;i<=m;i++)sum+=i;
for(int i=2;i<=n;i++){
sum+=i*m;
}
cout<<sum<<endl;
}
return ~~(0^_^0);
}
B
赛时我的写的1834ms 我以为不是正解 刚刚看了一下就是正解 可能是我的高精常数太大了???
#include <bits/stdc++.h>
using namespace std;
const int N = 5e3+10;
const int M = 1<<16;
const int mod = 1e9+7;
#define int long long
#define LL long long
#define endl '\n'
#define Endl '\n'
#define yes cout<<"YES"<<endl;
#define no cout<<"NO"<<endl;
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
bool cmp(vector <int> &A,vector <int> &B){ // 判断是否A > B
if(A.size() != B.size()) return A.size() > B.size(); // 如果A、B长度不相同,长度长的那个数大
for(int i = A.size() - 1;i >= 0;i --){ // 否则就要从最高位开始看(因为执行这个函数前,A和B数组都已经倒序,所以这里要从后往前看)
if(A[i] != B[i]) return A[i] > B[i]; // 如果A的当前位和B的当前位不相等,当前位大的更大
}
return true; // 如果A、B数组都相等,这里可以直接返回true,当然也可以直接输出0
}
vector <int> sub(vector <int> &A,vector <int> &B){ // A - B
int t = 0; // 每一位上相减得到的数
vector <int> C; // 最后的答案
for(int i = 0;i < A.size();i ++){ // 遍历一遍,和高精度加法不一样的是,只要遍历完A就行了,因为这里A肯定比B长
t = A[i] - t; // t要等于A的当前位减掉自己,因为上一位有可能出现借位的情况
if(i < B.size()) t -= B[i]; // 如果没有遍历完B,那么t减掉B的当前位
C.push_back((t + 10) % 10); // 更新C数组
// 这里如果没有借位,(t + 10) % 10就刚好等于t
// 如果这里有借位,(t + 10) % 10就会借一个10下来
if(t < 0) t = 1; // 如果t < 0,说明不够减,需要借位,把t赋值为1,就是在下一次执行中,A的当前位会减掉t
else t = 0; // 否则够减,赋值为0,不用借位
}
while(C.size() > 1 && C.back() == 0) C.pop_back(); // 删除前导0
return C; // 返回答案
}
signed main(){
fast
int T;cin>>T;
while(T--){
int n;cin>>n;
string a;cin>>a;
if(a=="1"){
cout<<1<<endl;
}else{
string b="1";
if(a[0]=='9'){
for(int i=2;i<=n;i++)b=b+'1';
}else{
for(int i=2;i<=n;i++)b=b+'0';
}
b=b+'1';
vector <int> A,B; // 两个数,因为减法是从最低位开始减,我们可以把两个数倒过来
for(int i = a.size() - 1;i >= 0;i --) A.push_back(a[i] - '0'); // 把a数组到过来存入A,记得a是string类型的数组,要减去'0'让它变成数字
for(int i = b.size() - 1;i >= 0;i --) B.push_back(b[i] - '0'); // 把b数组倒过来存入B
if(cmp(A,B)){ // 如果A > B
auto C = sub(A,B); // 那么可以直接相减
for(int i = C.size() - 1;i >= 0;i --)cout<<C[i];
}
else{ // 否则A < B,需要计算-(B - A)
auto C = sub(B,A); // 计算B - A
for(int i = C.size() - 1;i >= 0;i --)cout<<C[i];
}
cout<<endl;
}
}
return ~~(0^_^0);
}
C
这种区间+-已经很习惯性的考虑前缀和或者是差分了吧
我们可以把题干种三种操作就转化为:1.d1--&&di++ 2.di++ 3.d1++
我们先贪心的把所有第一种操作做完 剩下的就只有第二三种操作了
最后别忘了记录a1的值 再加上去就行了
#include <bits/stdc++.h>
using namespace std;
const int N = 5e3+10;
const int M = 1<<16;
const int mod = 1e9+7;
#define int long long
#define LL long long
#define endl '\n'
#define Endl '\n'
#define yes cout<<"YES"<<endl;
#define no cout<<"NO"<<endl;
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
signed main(){
fast
int T;cin>>T;
while(T--){
int n;cin>>n;
vector<int>a(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
}
int ans=0,sum=a[1];
for(int i=2;i<=n;i++){
int b=a[i-1]-a[i];
ans+=abs(b);
if(b>0)sum-=b;
}
ans+=abs(sum);
cout<<ans<<endl;
}
return ~~(0^_^0);
}
D
一眼二分&&dp 没啥好说的
#include <bits/stdc++.h>
using namespace std;
const int N = 5e3+10;
const int M = 1<<16;
const int mod = 1e9+7;
#define int long long
#define LL long long
#define endl '\n'
#define Endl '\n'
#define yes cout<<"YES"<<endl;
#define no cout<<"NO"<<endl;
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
signed main(){
fast
int n;cin>>n;
vector<int>f(n+1);//f[i]表示前i个桶至少要的时间
vector<int>a(n+1);
vector<int>s(n+1);
for(int i=1;i<=n;i++)cin>>a[i],s[i]=s[i-1]+a[i];
f[1]=a[1];
for(int i=2;i<=n;i++){
f[i]=max(f[i-1],(s[i]-1)/i+1);
}
vector<int>v;//每根管子对应的时长
for(int i=1;i<=n;i++){
v.push_back(max(f[i],(s[n]-1)/i+1));
}
int q;cin>>q;
while(q--){
int x;cin>>x;
if(lower_bound(v.begin(),v.end(),x,greater<>())!=v.end()){
cout<<lower_bound(v.begin(),v.end(),x,greater<>())-v.begin()+1<<endl;
}else cout<<-1<<endl;
}
return ~~(0^_^0);
}
A
不懂 猜的奇数无解 偶数 随便构造构造就有了
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
const int M = 1<<16;
const int mod = 1e9+7;
#define int long long
#define LL long long
#define endl '\n'
#define Endl '\n'
#define yes cout<<"YES"<<endl;
#define no cout<<"NO"<<endl;
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
signed main(){
fast
int T;cin>>T;
while(T--){
int n;cin>>n;
if(n%2){
cout<<-1<<endl;
}else{
cout<<0<<' '<<n/2<<' '<<n/2<<endl;
}
}
return ~~(0^_^0);
}
B
咋又是构造 随便观察一下样例就发现了
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
const int M = 1<<16;
const int mod = 1e9+7;
#define int long long
#define LL long long
#define endl '\n'
#define Endl '\n'
#define yes cout<<"YES"<<endl;
#define no cout<<"NO"<<endl;
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
signed main(){
fast
int T;cin>>T;
while(T--){
int n,m;cin>>n>>m;
int a[5]={1,0,0,1};
int b[5]={0,1,1,0};
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(i/2%2==0){
cout<<a[(j-1)%4]<<' ';
}else if(i/2%2){
cout<<b[(j-1)%4]<<' ';
}
}
cout<<endl;
}
}
return ~~(0^_^0);
}
C
简而言之 就是维护一个区间 要是后一个点在区间内就可以随便放 然后还要减掉前面的数 否则就更新区间
#include <bits/stdc++.h>
using namespace std;
const int N = 5e3+10;
const int M = 1<<16;
const int mod = 1e9+7;
#define int long long
#define LL long long
#define endl '\n'
#define Endl '\n'
#define yes cout<<"YES"<<endl;
#define no cout<<"NO"<<endl;
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
signed main(){
fast
int T;cin>>T;
while(T--){
int n;
cin >> n;
int a[n + 1];
int pos[n + 1];
for (int i = 0; i < n; i++) {
cin >> a[i];
pos[a[i]] = i;
}
int l = pos[0], r = pos[0];
int ans = 1;
for (int i = 1; i < n; i++) {
if (pos[i] < l)
l = pos[i];
else if (pos[i] > r)
r = pos[i];
else
ans = ans * (r - l + 1 - i) % mod;
}
cout << ans << endl;
}
return ~~(0^_^0);
}
D
是个dp吧 能看出来 但是最开始想的肯定都是n3的
我们考虑一个性质:
当一个数想要连续时 当且仅当他们相邻 或者相隔区间长度为偶数并且众数不大于n/2 这个很好想
状态表示:f[i]表示以ai为结尾的最长max 我们通过枚举f[i]并且后面区间可以消除 就可以get max
状态计算和n3做法一样枚举每一个前面的i即可
因为有了这个性质 所以说我们可以固定ai 然后少枚举一维
#include <bits/stdc++.h>
using namespace std;
const int N = 5e3+10;
const int M = 1<<16;
const int mod = 1e9+7;
//#define int long long
#define LL long long
#define endl '\n'
#define Endl '\n'
#define yes cout<<"YES"<<endl;
#define no cout<<"NO"<<endl;
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
signed main(){
fast
int T;cin>>T;
while(T--){
int n;cin>>n;
vector<int>a(n+1);
for(int i=1;i<=n;i++)cin>>a[i];
int w[n+10][n+10];
memset(w,0,sizeof w);
vector<int>t(n+1);
for(int i=1;i<=n;i++){
int mx=-1;for(int j=1;j<=n;j++)t[j]=0;
for(int j=i;j<=n;j++){
t[a[j]]++; mx=max(mx,t[a[j]]);
if(mx<=((j-i+1)>>1)&&((j-i)&1)) w[i][j]=1; //区间长度为偶数并且众数不超过n/2
}
}
vector<int>f(n+2);
f[1]=1;
for(int i=2;i<=n;i++)w[1][i-1]?f[i]=1:f[i]=-inf;
for(int i=1;i<=n;i++){
for(int j=i-1;j>=1;j-=2){
if(j==i-1&&a[i]==a[j])f[i]=max(f[i],f[j]+1);//间隔区间长度为0时
else if(a[i]==a[j]&&w[j+1][i-1])f[i]=max(f[i],f[j]+1);
}
}
int ans=0;
for(int i=1;i<=n;i++){
if(w[i+1][n]||i+1>n)ans=max(ans,f[i]);
}
cout<<ans<<endl;
}
return ~~(0^_^0);
}