Educational Codeforces Round 103 (Rated for Div. 2)
http://codeforces.com/contest/1476
A K-divisible Sum
题意:给你n和k,需要构造一个长度为n的数组a(a中数都为正整数)使得所有数之和是k的倍数,要使得a中最大的数最小,问这个最小数是多少
思路:首先a全放1和为n,全放2合为2n,如果n >= k那么n~2n之间必有k的倍数,否则先全放
⌊
k
/
n
⌋
\lfloor k/n \rfloor
⌊k/n⌋,之后选择一些位置加一必能刚好得到k
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t,n,k;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&k);
if(n >= k)
{
if(n % k == 0)
printf("1\n");
else
printf("2\n");
}
else
{
printf("%d\n",(k+n-1)/n);
}
}
return 0;
}
B Inflation
题意:给你n个数字p0,p1,…,pn-1,p0为商品初始价格,第一天价格变为p0+p1,记为sum1,第二天为p0+p1+p2,记为sum2,…,最后给你一个k,你可以每次将p0~pn-1中的一个数字加1,最终要使得对所有i(1<=i<=n-1),
p
i
s
u
m
i
−
1
<
=
k
%
\frac{p_i}{sum_{i-1}} <= k\%
sumi−1pi<=k%
思路:对于第i天如果不满足
p
i
s
u
m
i
−
1
<
=
k
%
\frac{p_i}{sum_{i-1}} <= k\%
sumi−1pi<=k%,则需要增加
s
u
m
i
−
1
sum_{i-1}
sumi−1,因为增加p1 ~ pi-1可能会让某一天变得不满足条件,让次数再次增加,而直接加到p0上便为最优解
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int t,n,k;
ll x,sum;
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&k);
scanf("%lld",&sum);
ll ans= 0 ;
for(int i = 1;i < n;++i)
{
scanf("%lld",&x);
ll tmp = (100*x+k-1)/k;
if(sum < tmp)
{
ans += tmp-sum;
sum = tmp;
}
sum += x;
}
printf("%lld\n",ans);
}
return 0;
}
C Longest Simple Cycle
题意:有n条链,每条链由ci个点依次连边组成,标号为1 ~ ci,第i(2 <= i <= n)条链的第1个节点与第i-1条链的第ai个节点连边,第ci个节点与第i-1条链的第bi个节点连边,问这样一个图中最大的简单环大小为多大
思路:首先假设ai<bi,第一条链的a2节点连向第二条链的1号节点,b2节点连向第二条链的c2号节点,中间a2直接一路连边到b2,依次扩展,如果环在第i条链收尾,则会增加长度ci-1,记录个最大值然后继续往下扩展,此时可能是之前的环扩展而来,继续扩展增加长度
a
i
+
1
−
1
+
c
i
−
b
i
+
1
a_{i+1}-1+c_{i}-b_{i+1}
ai+1−1+ci−bi+1 也可能从当前链开始,ai+1~bi+1依次连边重新开始扩展,二者取最大值,如果ai+1=bi+1,那么必须从当前链重新开始扩展否则不是简单环
#include<bits/stdc++.h>
#define ll long long
#define MAXN 100005
using namespace std;
int t,n;
ll a[MAXN],b[MAXN],c[MAXN];
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i = 1;i <= n;++i)
scanf("%lld",&c[i]);
for(int i = 1;i <= n;++i)
scanf("%lld",&a[i]);
for(int i = 1;i <= n;++i)
scanf("%lld",&b[i]);
ll ans = abs(a[2]-b[2]);
ll tmp = ans + 2;
for(int i = 2;i < n;++i)
{
ans = max(ans,tmp + c[i]-1);
if(a[i+1] == b[i+1])
tmp = 2;
else
tmp = max(tmp+c[i]-max(a[i+1],b[i+1]) + min(a[i+1],b[i+1])-1,abs(a[i+1]-b[i+1])) + 2;
}
ans = max(ans,tmp + c[n]-1);
printf("%lld\n",ans);
}
return 0;
}
D Journey
题意:有n+1座城市标号为0~n,相邻标号的两座城市有一条边,可能往左(i+1向i连边),也可能往右,你从一个城市出发,每走一步所有边的方向反向,可以重复经过同一个城市,问你从每一个城市出发,各自最多能访问多少个城市
思路:首先往一个方向走一步后边反向便能回来,返回后边和初始一样,所以可以分开看往左和往右最多到达多少个城市,现往右走,假设往左的边为0,右为1,则最远到达的必为101010这样交叉出现的边,由1开始,直接从后往前推便好,遇到0则不能往右答案为0,记录下交叉了多少次,遇到1赋值,往左同
#include<bits/stdc++.h>
#define MAXN 300005
using namespace std;
int t,n,a[MAXN],ans[MAXN];
char s[MAXN];
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%s",&n,s);
for(int i = 0;i < n;++i)
{
if(s[i] == 'L')
a[i] = 0;
else
a[i] = 1;
}
ans[n] = 0;
a[n] = a[n-1];
int tmp = 0;
for(int i = n-1;i >= 0;--i)
{
ans[i] = 0;
if(a[i+1] != a[i])
++tmp;
else
tmp = 1;
if(a[i] == 1)
ans[i] += tmp;
}
for(int l = 0,r = n-1;l < r;++l,--r)
swap(a[l],a[r]);
a[n] = a[n-1];
tmp = 0;
for(int i = n-1;i >= 0;--i)
{
if(a[i+1] != a[i])
++tmp;
else
tmp = 1;
if(a[i] == 0)
ans[n-i] += tmp;
}
for(int i = 0;i <= n;++i)
printf("%d ",ans[i]+1);
printf("\n");
}
return 0;
}