还没系统测试。仅供参考。
A. K-divisible Sum
题意:给定n,k。让找一个n个元素的数组,数组和可以整除k。并且数组中元素的最大值 最小。
思路:如果n == k。那显然是1。 如果n > k,分两种情况。n%k == 0。那么全是1,和就是k的倍数了。否则,必须要有一些2。去凑成余数。所以最大值是2。 接着考虑 n < k,至少要和加起来要等于一个k。(k+n-1)/n 就是答案。
AC代码:
#include <iostream>
#include <bits/stdc++.h>
#include <unordered_map>
#define int long long
#define mk make_pair
#define gcd __gcd
using namespace std;
const double eps = 1e-10;
const int mod = 1e9+7;
const int N = 3e6+7;
int n,m,k,t = 1,cas = 1;
int a[N],b[N];
signed main(){
cin>>t;
while(t--){
cin>>n>>k;
if(n >= k){
if(n%k == 0)cout<<1<<endl;
else cout<<2<<endl;
}else{
cout<<(n+k-1)/n<<endl;
}
}
return 0;
}
B. Inflation
题意:给一个数组,和一个k。要让这个数组保持这个性质。可以给一些数增加一些值。问最小的增加量。
如图,左边分子是a[i]分母是前i-1项和。右边分子是k,分母是100;保持这个性质就行了 。
思路:很容易发现,下面是前缀和嘛。 要让分数变小,肯定是前缀和越大越好。那肯定把所有的增量都增加到a[0]上去。不就行了。然后就是计算这个增量了。对于每一项。分子其实都是独立的。那么可以直接求出,保持这个比例。需要的前缀和是多少!然后与真实的前缀和的差值。就是当前这个点保持性质需要的增量。所有项要保持性质需要的的最大增量就是答案了。
AC代码:
#include <iostream>
#include <bits/stdc++.h>
#include <unordered_map>
#define int long long
#define mk make_pair
#define gcd __gcd
using namespace std;
const double eps = 1e-10;
const int mod = 1e9+7;
const int N = 3e6+7;
int n,m,k,t = 1,cas = 1;
int a[N],b[N];
signed main(){
cin>>t;
while(t--){
cin>>n>>k;
int tot = 0;
for(int i = 0 ; i < n ; i ++){
cin>>a[i];
tot += a[i];
}
for(int i = 0 ;i < n ; i ++){
}
int last = a[n-1];
int sum = 0;
int res = 0;
int maxx = 0;
tot -= a[n-1];
for(int i = n-2 ; i >= 0 ; i --){
sum = (100*last+k-1)/k;
last = a[i];
//cout<<sum<<" "<<tot<<endl;
int tmp = max(0LL,sum-tot);
maxx = max(maxx,tmp);
tot -= a[i];
}
cout<<maxx<<endl;
}
return 0;
}
C. Longest Simple Cycle
题意:n个柱子。每个柱子从上到下c[i]个点。然后相邻两个柱子之间都有两条边。分别是从c[i]的头上和脚上引出来的两条边。分别连接c[i-1]的a和b点。 有点绕。最终这样形成一个图型的结构,求最大的环大小。
思路:贪心。从最后一根柱子往前访问过去。最后一根柱子就有 c[i]-1条边了。然后往前走。分情况讨论。
1. 两个落脚点在同一个位置。那这个环就已经结束了。没有选择的余地。从新开始另一个环。从这个点 向上下走就行了。
2. 上面的落脚点在上面。下面的在下面。那么就接着上面往上走,下面往下走。可以把这个环一直延续下去。直到走到1那种情况 或者走到第一根柱子结束。
3. 显然,与2相反。这个也很简单。交换一下 上下就好了。swap(up,down)。
然后在求解的过程中。用now记录当前已经在环上的边的数量。maxx记录全局最大值。 不过遍历的过程要注意now的贪心法则。碰到第一种情况。 不用贪心。没得选。 但是对于2,3来说。有可能 now的值还没有 中间那部分没走的多! 那以中间某个点为起点,另起一个环,岂不是更大了嘛。这时候就得更新now的值。 要注意第一根柱子的特殊性。除了up-down之内的点。 是不可能在环上的。那些点全当不存在就是了。特判一下就行。
AC代码:
#include <iostream>
#include <bits/stdc++.h>
#include <unordered_map>
#define int long long
#define mk make_pair
#define gcd __gcd
using namespace std;
const double eps = 1e-10;
const int mod = 1e9+7;
const int N = 3e6+7;
int n,m,k,t = 1,cas = 1;
int a[N],b[N],c[N];
signed main(){
cin>>t;
while(t--){
cin>>n;
for(int i = 0 ; i < n ; i ++) cin>>c[i];
for(int i = 0 ; i < n ; i ++) cin>>a[i];
for(int i = 0 ; i < n ; i ++) cin>>b[i];
int maxx = 0;
int last = 0;
int now = c[n-1]-1;
int up = 0;
int down = 0;
for(int i = n-1 ; i >= 1 ; i --){
up = a[i];
down = b[i];
now += 2;
if(up == down){
maxx = max(maxx,now);
if( i >= 2){
now = c[i-1]-1;
}else now = 0;
}else if(up > down){
swap(up,down);
maxx = max(maxx,now+abs(up-down));
if( i >= 2){
now += up-1;
now += c[i-1]-down;
now = max(now,c[i-1]-1);
}
}else{
maxx = max(maxx,now+abs(up-down));
if( i >= 2){
now += up-1;
now += c[i-1]-down;
now = max(now,c[i-1]-1);
}
}
}
maxx = max(maxx,now);
cout<<maxx<<endl;
}
return 0;
}
D. Journey
题意:有n+1个城市。n条有向边,连接 i -> i+1。然后现在商人以一个点为起点开始遍历。每移动一次,所有的边就会调转方向。问以所有i为起点。能访问到的城市的数量。
思路:分类讨论。前后缀和。因为每走一次就会方向。所以不管走到哪都能沿路返回到起点。假设现在在x点。然后往左走。走到不能走了。再回来。回到起点。就像什么也没发生一样。但是已经遍历完了左边能遍历的点。接着对右边进行遍历。所以求解肯定是分左右分别进行讨论。然后考虑到底能走哪些。 对于左边。 如果是 LRLRLX,就可以一直走。只要LR交替。就能一直走。不过前提是起点的左边必须是L。同理 右边也是RLRL交替就可以走。 起点右边必须是R。最后再特殊考虑一下左右两端点。LR交替出现的次数,用前缀和维护就好了。前后各维护一次。
AC代码:
#include <iostream>
#include <bits/stdc++.h>
#include <unordered_map>
#define int long long
#define mk make_pair
#define gcd __gcd
using namespace std;
const double eps = 1e-10;
const int mod = 1e9+7;
const int N = 3e6+7;
int n,m,k,t = 1,cas = 1;
int a[N],b[N],c[N];
int sum1[N];
int sum2[N];
int res[N];
signed main(){
cin>>t;
while(t--){
cin>>n;
string s;
cin>>s;
sum1[0] = 1;
for(int i = 1 ; i < n ; i ++){
if(s[i] == s[i-1]) sum1[i] = 1;
else sum1[i] = sum1[i-1]+1;
}
sum2[n-1] = 1;
for(int i = n-2; i >= 0 ; i --){
if(s[i] == s[i+1]) sum2[i] = 1;
else sum2[i] = sum2[i+1]+1;
}
for(int i = 1; i <= n-1 ; i ++){
res[i] = 1;
//cout<<s[i-1]<<" "<<i<<" "<<s[i]<<endl;
//cout<<sum1[i-1]<<" "<<sum2[i]<<endl;
if(s[i-1] == 'L') res[i] += sum1[i-1];
if(s[i] == 'R') res[i] += sum2[i];
}
if(s[0] == 'R'){
res[0] = sum2[0]+1;
}else{
res[0] = 1;
}
if(s[n-1] == 'L'){
res[n] = sum1[n-1]+1;
}else{
res[n] = 1;
}
for(int i = 0 ; i <= n ; i ++)
cout<<res[i]<<" ";
cout<<endl;
}
return 0;
}