因为题目保证了有解,所以我们枚举一下 k k k就行了。
#include
using namespace std;
typedef long long ll;
int main()
{
int t; cin >> t;
while (t--)
{
ll n; cin >> n;
ll sum = 4;
while (n % (sum - 1) != 0)
sum *= 2;
cout << n / (sum - 1) << endl;
}
return 0;
}
看起来有点吓人,其实也很好想。看样例就能看出来。
首先如果 n / 2 n/2 n/2是奇数肯定不成立。前面是偶数,后面是奇数,不相等。
如果 n / 2 n/2 n/2是偶数我们就尝试构造。偶数就 2 , 4 , 6 , 8 2,4,6,8 2,4,6,8这样输出,奇数就 1 , 3 , 5 , 7 1,3,5,7 1,3,5,7这样输出。然后在最后一个数把前面的差补全就好了。
#include
using namespace std;
typedef long long ll;
int main()
{
int t; cin >> t;
while (t--)
{
int n; scanf("%d", &n);
if (n / 2 % 2) printf("NO\n");
else
{
printf("YES\n");
for (int i = 1; i <= n / 2; ++i)
printf("%d ", 2 * i);
for (int i = 1; i <= n / 2 - 1; ++i)
printf("%d ", 2 * i - 1);
printf("%d\n", n / 2 * 3 - 1);
}
}
return 0;
}
这题因为限制要找最长的,所以我们见到异号的就加就可以了。
如果同号的话更新一下最大值。
#include
using namespace std;
typedef long long ll;
int main()
{
int t; cin >> t;
while (t--)
{
int n; cin >> n;
static ll a[200010];
for (int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
vector <ll> sav; ll sum = a[1];
sav.push_back(a[1]);
for (int i = 2; i <= n; ++i)
{
int size = sav.size();
if (sav[size - 1] * a[i] > 0)
{
if (sav[size - 1] < a[i])
{
sum = sum - sav[size - 1] + a[i];
sav[size - 1] = a[i];
}
}
else sav.push_back(a[i]), sum += a[i];
}
printf("%lld\n", sum);
}
return 0;
}
这场没想到的是D居然没出。思路在接近一个月前是接触过的,不过比赛没想到。明天会补。
不过这次因为前三题出得飞快居然上了70分。舒服了。
不过罚坐了一个半小时多
今天是个上分的好天气 真的
差分前缀和。比赛的时候想的是枚举 x x x,考虑这个 x x x有哪几种数对会对它有贡献。两个数都大于等于 x x x贡献为2,剩下的除非等于其它贡献都为1。不过这真的没办法写…
正解也是枚举 x x x,不过考虑的是每对数对 x x x的贡献。观察发现对于某对数 ( a , b ) (a,b) (a,b),修改其中某一个数的值最小能改成 m i n ( a , b ) + 1 min(a,b)+1 min(a,b)+1,最大能改成 m a x ( a , b ) + k max(a,b)+k max(a,b)+k。于是在这个区间里这对数的贡献为1。不过 a + b a+b a+b的贡献记得修改为0。
在这个区间之外的贡献都为2。然后我们就可以差分了。
对于在区间外的贡献我们考虑在 d i f [ 1 ] dif[1] dif[1]中加二。然后直接跑一遍前缀和,取个最小值。
(过几天也出道差分的题玩玩www)
#include
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 10;
const int INF = 0x3f3f3f3f;
int main()
{
int t; cin >> t;
while (t--)
{
int n, k; scanf("%d%d", &n, &k);
static int a[MAXN];
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
int dif[2 * MAXN] = {0};
for (int i = 1; i <= n / 2; ++i)
{
dif[1] += 2;
dif[min(a[i], a[n - i + 1]) + 1]--;
dif[max(a[i], a[n - i + 1]) + k + 1]++;
dif[a[i] + a[n - i + 1]]--;
dif[a[i] + a[n - i + 1] + 1]++;
}
int ans = INF;
for (int i = 1; i <= 2 * k; ++i)
dif[i] = dif[i - 1] + dif[i], ans = min(ans, dif[i]);
cout << ans << endl;
}
return 0;
}
这题还有一点需要注意。 d i f dif dif数组这种需要初始化的如果空间够尽量不要开到static里。
对于大数组memset的时间消耗非!常!大!
之前听说fill_n跑得很快。不清楚是不是真的。
一开始开到static里+memset时间是982ms,差一点就超时了。
删掉memset之后直接降到545ms,快了接近一倍。