Problem 1: 魔法阵~
时间限制:1000MS
内存限制:128000KB
思路:
由于要求删除后仍然是一个正多边形,
这就保证剩余的点数一定是n的因子,
只有这样才能均匀删除。
所以我们只需要枚举n的因子作为剩余多边形的顶点数,
对答案取max即可。
一个数的因子数个数是log级别的,
而且每次选择魔法阵的时候每个点
只属于当前因子的某一个魔法阵,
所以每个点只访问一次,
所以总复杂度为 O ( n log n ) O(n\log n) O(nlogn)。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <vector>
#include <ctime>
#include <cctype>
#include <bitset>
#include <utility>
#include <sstream>
#include <complex>
#include <iomanip>
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
int n,t[20010],yz[20010],sum,ct;
void ys(int x)
{
for(int i = 2; i < x; i++)
if(!(x % i))
yz[ct++] = i;
}
int main()
{
cin>>n;
for(int i = 1; i <= n; i++)
{
cin>>t[i], sum += t[i];
}
ys(n);
if(n == 3 || !ct) {
cout<<sum<<endl; return 0;}
for(int i = 0; i < ct; i++)
{
int gs = yz[i], begin = 1;
while(gs--)
{
int tot = 0,cnt = 0;
for(int j = begin; j <= n; j += yz[i]) tot += t[j], cnt++;
if(cnt >= 3) sum = max(sum, tot);
begin++;
}
}
printf("%d\n", sum);
return 0;
}
Problem 2: 小biu放牛
时间限制:1000MS
内存限制:128000KB
PS:题目的输出格式不要管他,什么码头都来了!
思路:
二分+贪心。我们要贪心把牛放在最前面,
那么牛头的位置就是i-t-x;但是题目要求不能重叠,
用max比较一下可以确定牛头的位置在哪,这样保证了靠前。
然后我们可以用头部的位置,判断是否越界。
最后要判断一下尾部有没有越界,
时间复杂度为 O ( n log n ) O(n\log n) O(nlogn);
#include <cstdio>
#include <iostream>
#include <cmath>
using namespace std;
const int N=5e4+10;
int a[N];
int n, x, m;
bool check(int mid)
{
int h=0, t=0;
for(int i = 1; i <= n; i++)
{
h = max(t, a[i] - mid - x);
if(abs(h - a[i] + x) > mid) return false;
t = h + 2 * x;
if(t > m) return false;
}
return true;
}
int main()
{
scanf("%d%d%d", &n, &x, &m);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
int l = 0, r = m;
while(l <= r)
{
int mid = l + r >> 1;
if(check(mid)) r = mid - 1;
else l = mid + 1;
}
if(l > m) printf("-1\n");
else printf("%d\n", l);
}
/*
3 2 16
1
3
14
*/
Problem 3: 小A的游戏
时间限制:1000MS
内存限制:256000KB
(为什么我觉得这道题比前两道还水?)
思路:
考虑如果出现两个相同字符之间的距离小于等于k时,
小A一定可以删除这连续的一段,让小B无法判断他
删除的是前面的字符还是后面的字符,否则则小B一定能判断。
所以当且仅当出现两个相同字符之间的距离小于等于k时,
答案为Uncertain。否则答案为Certain。
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
int t, k, last[30];
bool flag;
string s;
int main()
{
scanf("%d", &t);
while(t--)
{
memset(last, -1, sizeof(last)), flag=0;
cin>>s;
scanf("%d", &k);
int l = s.size();
if(k == l) {
printf("Certain\n"); continue;}
else
{
for(int i = 0; i < l; i++)
{
if(last[s[i] - 'a'] != -1 && i - last[s[i] - 'a'] <= k)
{
printf("Uncertain\n"), flag=1; break;}
last[s[i] - 'a'] = i;
}
}
if(!flag) printf("Certain\n");
}
return 0;
}
/*
1
snuke
2
*/
Problem 4: 小Biu闯关
时间限制:1000MS
内存限制:128000KB
思路:
首先,必须承认考场爆零了。
0分暴力:
考虑一个区间[A,B],能表达的数为[A2,B2], [A3,B3]…[AK,BK].
那么我们无脑地去K,直到A*K>Y为止。
考虑任意一个区间的最大贡献,肯定是为:
m i n ( y , k ∗ 1 l l ∗ b ) − m a x ( x , k ∗ 1 l l ∗ a ) + 1 min(y, k * 1ll * b) - max(x, k * 1ll * a) + 1 min(y,k∗1ll∗b)−max(x,k∗1ll∗a)+1
用个ans将这K个区间的贡献加个总,输出即可。
但是绝对会爆零!!!
100分
我们想想,难道一定要到AK>Y为止,
肯定不是了,当kA<=(k-1)*B时,区间就发生重合,
之后的数就全部都能凑出来。
那我们改结束条件为这个,就欧了!!!
#include <cstdio>
#include <iostream>
#define ll long long
using namespace std;
int t;
ll a, b, x, y;
int main()
{
scanf("%d", &t);
while(t--)
{
ll ans = 0;
scanf("%lld%lld%lld%lld", &a, &b, &x, &y);
ll begin = (b < x? x / b + 1: 1);
for(ll k = begin; k; k++)
{
ll l = a * k, r = b * k, nl = a * (k + 1);
if(l > y) break;
if(nl <= r) {
ans += (y - max(l, x) + 1); break;}
ans += (min(y, r) - max(x, l) + 1);
}
printf("%lld\n", ans);
}
return 0;
}