A水题。
————————————————————————————————————————————
B题水题,这里其实就是,把所有的情况展开,就可以发现公式为(n-1)(an2+an-12…+a12)+(交叉项的所有和)。就是维护交叉项。交叉项可以拿前缀和来维护。
sum(sum-a[i])就是a[i]与其他所有的乘积,再sum-=a[i]就可以不断循环下去,o(n)就解决了。
水题。
C题,,一秒就能过。。
D题,感觉稍微难一点,不过也就是以为差分数组就能过了。
维护每个区间有多个点重合了。最后统计最大值。
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
int n;
struct node{ int s, e; }sch[100005];
int chaf[100005];
int sum[100005];
int main()
{
cin >> n;
int maxx = 0;
up(i, 0, n)
{
scanf("%d%d", &sch[i].s, &sch[i].e);
maxx = max(maxx, sch[i].e);
}
up(i, 0, n)
{
chaf[sch[i].s]++;
chaf[sch[i].e]--;
}//差分数组,注意e--,因为结束时间是可以成为开始时间的
int ans = 1;
upd(i, 0, maxx)
{
if(i>0)
sum[i] = sum[i - 1] + chaf[i];
else sum[i] = chaf[i];
}//差分数组扫一遍,得到每个点的值,即每个时间有多少个重合了
upd(i, 0, maxx)
{
ans = max(ans, sum[i]);
}
cout << ans << endl;
return 0;
}
E题没有做,知道是马拉车算法。待补。
已补,裸模板,稍微加点变化。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
char model[10010];
char s[5005];
int lens[10010];
int cnt, len;
void init(int len)
{
model[cnt++] = '%';
up(i, 0, len)
{
model[cnt++] = '#';
model[cnt++] = s[i];
}
model[cnt++] = '#';
}
int manecher()
{
lens[0] = 0;
int sum = 0;
int mx = 0;
int st = 0;
up(i, 1, len)
{
if ((i & 1 )== 0)continue;
if (i < mx)lens[i] = min(lens[2 * st - i], mx - i);
else lens[i] = 1;
while (fabs(model[i - lens[i]] - model[i + lens[i]]) == 'a' - 'A'||model[i-lens[i]]=='#')lens[i]++;
if (lens[i] + i > mx)
{
mx = lens[i] + i;
st = i;
sum = max(sum, lens[i]);
}
}
return sum - 1;
}
int main()
{
cin >> s;
init(strlen(s));
len = cnt;
cout << manecher()<<endl;
return 0;
}
F题,线段树,待补
已补
早知道当时比赛的时候做这道题了,线段树上乱搞就能过了
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
int n, q;
const int N = 2e5 + 5;
ll tree[4 * N];
bool one[4 * N];
ll gcd(ll a, ll b)
{
return b == 0 ? a : gcd(b, a%b);
}
void pushup(int root) {
tree[root] = gcd(tree[root << 1], tree[root << 1 | 1]);
one[root] = one[root << 1] && one[root << 1 | 1];
}
void build(int l,int r,int root){
int mid = (l + r) >> 1;
if (l == r)
{
scanf("%lld", &tree[root]);
one[root] = tree[root] == 1;
return;
}
build(l, mid, root << 1);
build(mid + 1, r, root << 1 | 1);
pushup(root);
}
void update(int l, int r, int a,int b,int root)
{
if (one[root])//剪枝,不然时间爆炸了
{
return;
}
if (l == r)
{
tree[root] =(ll) sqrt(tree[root]);
if (tree[root] == 1)one[root] = 1;
return;
}
int mid = (l + r) >> 1;
if (a <= mid)update(l, mid, a, b, root << 1);
if (b > mid)update(mid + 1, r, a, b, root << 1 | 1);
pushup(root);
}
ll querry(int l, int r, int a, int b, int root)
{
if (one[root])return (ll)1;
int mid = (l + r) >> 1;
if (l >= a && r <= b)return tree[root];
ll g = 0;
if (mid < b)g = gcd(g, querry(mid + 1, r, a, b, root << 1 | 1));
if (a <= mid)g = gcd(g, querry(l, mid, a, b, root << 1));
return g;
}
int main()
{
cin >> n;
build(1, n, 1);
cin >> q;
int t;
int x, y;
while (q--)
{
scanf("%d", &t);
if (t == 0)
{
scanf("%d%d", &x, &y);
update(1, n, x, y,1);
}
else
{
scanf("%d%d", &x, &y);
cout << querry(1, n, x, y, 1)<<endl;
}
}
return 0;
}
G题水题,简单博弈论。
巴士博弈模板。
只不过要把0改成1,最后留下一个肯定必败
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
int t;
int p, m;
int main()
{
cin >> t;
while (t--)
{
cin >> p >> m;
if (p % (m + 1) == 1)cout << "Bob" << endl;
else cout << "Alice" << endl;
}
return 0;
}
H题,,和B题难度55开吧。
J题,简单dp
大概就是从1开始往后不断扫一遍,不断去遍历自己的倍数的点,类似于埃氏筛选的感觉,因为当前点肯定是已经最优值,可以用它来不断松弛后面的点。虽然是双线边,不过思考一下就知道走回头路肯定比直接到慢得多。
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
const int N = 5e5 + 10;
//bool used[N];
ll dp[N];
int n;
void init(int n)
{
dp[1] = 0;
upd(i, 1, n)
{
for (int j = 2*i; j <= n; j += i)
{
dp[i] = min(dp[i], dp[j] + (ll)(j - i)*(j - i));//这里是当时脑残了,不过不影响
dp[j] = min(dp[j], dp[i] + (ll)(j - i)*(j - i));
}
}
}
int main()
{
cin >> n;
fill(dp, dp + N, 1e15);
init(n);
upd(i, 1, n)
printf("%lld ", dp[i]);
return 0;
}
J题
定义dist为|i2-j2|+|ai2-aj2|,现在求给出的所有pair中,dist最大的那个。
第一时间上了差分数组。。。然后维护连续区间的和就能够表示ai2-aj2,但是大小关系不确定,而且会有i,j的影响如果i,j大了的话。
说实话被排行榜影响了,觉得很难。。
然后仔细思考发现其实分开两种情况讨论就行了。
假设i<j,就有,dist=|ai2-aj2|+j2+i2。
拆开就是两种情况。
然后分别维护,xx+ii的情况和ii-xx。
然后两种情况的最大最小值之差取大的那个就好了。可以证明这样是对的。
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
int n;
int t;
ll x;
int main()
{
cin >> t;
while (t--)
{
cin >> n;
ll minnadd = 9e18;
ll maxmis=-9e18;
ll maxadd=-9e18;
ll minnmis = 9e18;
upd(i, 1, n)
{
scanf("%lld", &x);
minnadd = min(ll((ll)i*i + x * x), minnadd);
maxadd = max(ll((ll)i*i + x * x), maxadd);
minnmis = min(minnmis, ll((ll)i*i - x * x));
maxmis = max(maxmis, ll((ll)i*i - x * x));
}
cout << max(maxadd - minnadd, maxmis - minnmis)<<endl;
}
return 0;
}
K题,贪心算法。被卡了好久。。一直在模拟,结果,一直错。。
问的是,将n分成两个数字a,b,求a,b的各位之和的最大值。我们可以知道的
假如给一个数字,把他分成每一位来看,他必然可以看成是,除了第一位以外,其他为看成是
10+n(1<=n<=8) 因为不可能有两个数字相加等于19。
所以我们贪心先,贪一个(n-1)个9组成的数组,例如给的5002,贪心999。
那么这样做就可以转化成我们上面说的那种方法,5002-999,让除了第一位的每一位,变成了10+当前为,如果当前位置是9,那么0就是这个位置上最大的。
因为每一个数位上相加可以是10-18,所以我们贪心最大肯定是向前借一位,当前为+10,这样前一位才-1,整体加9,所以这样做肯定是最大。
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
int t;
ll n;
ll sum = 0;
ll update(int len)
{
ll k = 0;
up(i, 0, len)
{
k = k * 10 + 9;
sum += 9;
}
return k;
}
int main()
{
cin >> t;
while (t--)
{
sum = 0;
cin >> n;
ll n1 = n;
int len = 0;
while (n)
{
n /= 10;
len++;
}
ll temp=update(len - 1);
n1 -= temp;
while (n1)
{
sum += n1 % 10;
n1 /= 10;
}
cout << sum << endl;
}
return 0;
}
可惜没有全部写完啊五个小时,可惜了,自己还有很多不足,特别是数论。今后还是多研究下数论吧哎。