E.soyorin的数组操作(easy)
题面:
soyorin有一个长度为 nnn 的数组,她每次操作可以选择一个不超过 n 的偶数 k ,使得 ai := ai+i (1ik)。
soyorin想知道她是否可以通过任意次操作将数组变成非降序。
思路:
如果说n为偶数,那么一定可以完成,每次进行加法计算,它们之前的差值都会变小。
如果说n为奇数,那么最后一个数不能进行加法计算,这时候就要开始进行操作了。因为数据比较大,如果从后往前进行判断,直接把当前的数变成比前一个小的最大值。直接统计当前的数应该加多少遍,如果直接改变数组里面的值那么就会爆掉。当然如果数组开int128那当我没有说,但是如果你开了int128就要用read()函数进行读取数数据。
#include <bits/stdc++.h> #include <iostream> using namespace std; const int N=1e6+10; #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,n,a) for(int i=n;i>=a;i--) #define endl '\n' typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> PII; #define int long long int a[N]; void solve() { int n; cin >> n; for(int i=0;i<=n+1;i++) a[i]=0; for(int i=1;i<=n;i++) cin >> a[i]; if(n%2==0) { cout << "YES" << endl; return ; } int flag=true; int cnt=0; for(int i=n-1;i>=1;i--) { if(i%2==0) { __int128 x=(a[i+1]+cnt*(i+1)); __int128 y=(a[i]+cnt*i); if(y>x) { flag=false; break; } int k=(x-y)/i; cnt+=k; } else if(i%2==1) { __int128 x=a[i]+i*cnt; __int128 y=a[i+1]+(i+1)*cnt; if(x>y) { flag=false; break; } } } if(flag) cout << "YES" << endl; else cout << "NO" << endl; } signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int T=1; cin >> T; while(T--) solve(); }
F.soyorin的数组操作(hard)
题面:
soyorin有一个长度为 nnn 的数组,她每次操作可以选择一个不超过 nnn 的偶数 kkk ,使得 ai:=ai+i (1ik)。
soyorin想知道她将数组变成非降序的最小操作次数,若无解则输出 -1。
思路:
你只需要从左往右遍历一遍,求一下当前的数比下一个数大多少,这样我只要在这遍加max那么就变成相等的了。那么现在我只要判断一个是否可以成立,如果成立那么只直接输出相差的最大值,否则就直接输出-1。(判断的代码同上)
#include <bits/stdc++.h> #include <iostream> using namespace std; const int N=1e6+10; #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,n,a) for(int i=n;i>=a;i--) #define endl '\n' typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> PII; #define int long long int a[N]; void solve() { int n; cin >> n; for(int i=0;i<=n+1;i++) a[i]=0; for(int i=1;i<=n;i++) cin >> a[i]; int ans=0; for(int i=1;i<n;i++) ans=max(ans,a[i]-a[i+1]); if(n%2==0) { cout << ans << endl; return ; } int flag=true; int cnt=0; for(int i=n-1;i>=1;i--) { if(i%2==0) { __int128 x=(a[i+1]+cnt*(i+1)); __int128 y=(a[i]+cnt*i); if(y>x) { flag=false; break; } int k=(x-y)/i; cnt+=k; } else if(i%2==1) { __int128 x=a[i]+i*cnt; __int128 y=a[i+1]+(i+1)*cnt; if(x>y) { flag=false; break; } } } if(flag) cout << ans << endl; else cout << -1 << endl; } signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int T=1; cin >> T; while(T--) solve(); }
J.rikki的数组陡峭值
题面:
rikki定义一个数组的陡峭值为:数组相邻元素差的绝对值之和。例如 [1,1,4,5,1,4] 的陡峭值为 |1-1|+|1-4|+|4-5|+|5-1|+|1-4| = 0+3+1+4+3 = 11。
rikki现在有一个数组 aaa ,其中每个元素 ai 都可以在 [li,ri]中选择一个整数,求最小的陡峭值。
思路:
就是说在每个区间顺序取一个数,然后取一下最小值,用的是合并区间的思路
#include <bits/stdc++.h> #include <iostream> using namespace std; const int N=1e6+10; #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,n,a) for(int i=n;i>=a;i--) #define endl '\n' typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> PII; #define int long long void solve() { int n; cin >> n; int l[N],r[N]; for(int i=1;i<=n;i++) cin >> l[i] >> r[i]; int L=l[1]; int R=r[1];//初始化两个边界 int ans=0;//记录不同合并的区间的值 for(int i=2;i<=n;i++) { L=max(L,l[i]);//不断地更新左边界 R=min(R,r[i]);//不断地更新右边界 if(L>R) { ans+=L-R; R=min(r[i],R);//取最小的边界 L=max(l[i],R);//和L相比取最大的边界 R=L; } } cout << ans << endl; } signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int T=1; //cin >> T; while(T--) solve(); }
K.soyorin的通知
题面:
soyorin有一个消息,她要把这个消息通知给 n个人,初始时没有人被通知过。 soyorin可以花费 p 的代价将消息通知给 1 个人,也可以花费 ai 的代价让第 i个人将消息通知给至多 bi个人
(前提是第 i个人已经被通知过,并且这个操作的次数不限)。
soyorin想知道最少花费多少代价可以将消息通知给 n个人。
思路:
这就相当于一个完全背包,但是你要先初始化一下,因为p的话,他刚开始通知一个人,这个是必须要用的,可能用通知1~n个人用p的代价
因为求的是最小的个代价可以通知n个人,然后你的边界就要和0进行取一下最大值,这样最后f[n]才能保证n个人
#include <bits/stdc++.h> #include <iostream> using namespace std; const int N=1e6+10; #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,n,a) for(int i=n;i>=a;i--) #define endl '\n' typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> PII; #define int long long int f[N]; void solve() { int n,p; cin >> n >> p; for(int i=1;i<n;i++) f[i]=i*p; for(int i=1;i<=n;i++) { int a,b; cin >> a >> b; for(int j=0;j<n;j++) f[j]=min(f[j],f[max(0LL,j-b)]+a); } cout << f[n-1]+p << endl; } signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int T=1; //cin >> T; while(T--) solve(); }