如果写错了求求不要 啊呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜
云浅太菜啦/kel,只做了ABD/kel
Description
- 给两个正整数
- 要求构造一个长为 的正整数数列 使得 ,且使得 最小,输出 。
- 组数据,
Solution
首先考虑一下这个数列中所有数之和最小值,显然是 的情况,即 最小为 。
最大肯定是可以想搞多大搞多大的qwq
然后显然若 且 ,那么必定可以构造出长为 的正整数数列使得这个数列中所有数的和为 。
那么分类一下:
如果 ,那么肯定可以构造出数列 使得 。
然后让最大值最小,那其实就是差不多让这个数列中的数平均一点嘛qwq。
那最大值就是 。
如果 ,当 时,直接放 个 即可。
当 时,考虑放 个 ,剩下的全放 ,此时有 ,能被 整除。
不难证明 就是此时的最优解。所以直接输出 。
PS:其实 时还可以把 直接硬改成 ,然后 ,转回第一种情况qwq。
总之这题方法挺多的,总之这题比较水qwq。
Code:
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
int n,k;
int T;
int ceill(int a,int b){
if(a%b==0){
return a/b;
}
else return (int)(a/b)+1;
}
int main(void){
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&k);
if(n<=k){
printf("%d\n",ceill(k,n));
}
else{
if(n%k==0)printf("%d\n",1);
else{
printf("%d\n",2);
}
}
}
return 0;
}
Description
- 给 个数 和一个数
- 你可以把任意的 加上任意正整数
- 操作完之后必须满足 有
- 要求求出最小的给这些数加上的值。
- 组数据,
Solution
珂以二分,也可以贪心qwq
这里讲一下贪心的做法w
首先很好想到的是维护一下前缀和 ,那么此时就是要求 。
(为了避免精度问题和一堆奇奇怪怪的问题,我们在这里把它化简成 。)
然后我们从前往后扫一遍整个序列 ,如果发现有不满足条件的,容易发现此时给第一个数加上尽可能大的值是一个很好的方案。
其实感性证明/理解一下就是:若 ,那我们必须把 变得更大一些,也就是把前 个数增大。
然后如果增大的不是第一个的话,如果我们增大了 ,很有可能我们增大的那个 又会太大以至于 ,不满足要求=_=
而综合来看,只有我们增大 之后,才绝对不会产生任何负面影响qwq。
严格的证明根据这个思路基本也能证,这里就说一下思路吧w。
那所以我们每次发现一个不满足要求的 ,直接改第一个即可。
需要增加的值也不难算,就是 。
然后这里我还闲着没事维护了一个树状数组来单点修改查询前缀和,吃了点罚时(草云浅为啥这么菜脑子还这么抽啊)
Code:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define int long long
#define MAXN 105
using namespace std;
int t;
int n,k;
int a[MAXN];
int s[MAXN];
bool cmp(int a,int b,int kqwq){
return kqwq*a>=100*b;
}
struct BIT{
int c[MAXN<<2];
inline int lowbit(int x){
return x&(-x);
}
inline void PreFix(){
memset(c,0,sizeof(c));
}
inline void modify(int x,int k){
for(int i=x;i<=n;i+=lowbit(i)){
c[i]+=k;
}
}
inline int query(int x){
int ans=0;
for(int i=x;i;i-=lowbit(i)){
ans+=c[i];
}
return ans;
}
};
BIT tree;
int ceill(int a,int b){
if(a%b==0){
return a/b;
}
else return (int)(a/b)+1;
}
signed main(void){
scanf("%lld",&t);
while(t--){
tree.PreFix();
int ansqwq=0;
scanf("%lld%lld",&n,&k);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
tree.modify(i,a[i]);
}
for(int i=2;i<=n;i++){
int sum=tree.query(i-1);
if(!cmp(sum,a[i],k)){
tree.modify(1,ceill(100*a[i],k)-sum);
ansqwq+=ceill(100*a[i],k)-sum;
}
}
printf("%lld\n",ansqwq);
}
return 0;
}
啊啊啊好想鸽子啊咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕
简要提一下思路吧,明早下午起来再补完整题解qwq
首先有个结论:不难发现让 这样交替出现下去是可以一直走下去并且完美返回的w
然后一旦断掉了,就比如 ,那么就必然不能再往后走了。
于是问题就变成了:对于每一个 ,求出 左边最长的、连续的、交替往复出现的 和 长度,右边同理。然后把左右长度加起来再加一(自己也算一个)即可。
暴力求解是 的。
然而 总和为 ,被分成 份的话每份应该挺小的,那平方一下也不会很大qwq
再加上 时限,而且这个算法实际效率应该比 快很多,所以云浅当时其实想过直接暴力卡常艹过去(
不过后来在神仙劝阻/指导下还是搞了正解qwq
就是这个东西其实是可以预处理的qwq
以预处理左边为例:令 为 左边最长的、连续的、交替往复出现的 和 的长度。
由于是向左,所以其实最后在 左边那个字符必须是 ,不然动不了=_=
然后搞一通:
int qwq=0;
for(int i=1;i<=n;i++){
qwq+=(str[i]!=str[i-1]);
if(str[i]==str[i-1])qwq=1;
if(str[i]=='L')pre[i]=qwq;
else pre[i]=0;
}
基本上就预处理完了。
右边的话其实差不多,只不过注意要把 初始化带上,再注意亿点点细节即可。
啊睡大觉去了QAQ,去梦里和珂珂酱贴贴了qwq