比赛链接:http://codeforces.com/contest/813
A. The Contest
题目比较长,读懂后,模拟即可。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010;
int n, m, x, l, r, sum;
int main()
{
while(~scanf("%d",&n)){
sum=0;
for(int i=0; i<n; i++){
scanf("%d",&x);
sum+=x;
}
scanf("%d",&m);
int ans = 0;
bool flag = 0;
for(int i=0; i<m; i++){
scanf("%d%d",&l,&r);
if(flag) continue;
if(l>=sum&&r>=sum){
ans = l;
flag = 1;
}
else if(r>=sum&&l<sum){
ans = sum;
flag = 1;
}
}
if(flag==1) printf("%d\n", ans);
else printf("-1\n");
}
return 0;
}
B. The Golden Age
枚举暴力
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL x,y,l,r;
LL mul(LL x, LL y){
if(double(x)*(double)y>=1e18) return r+1;
return x*y;
}
vector <LL> v;
int main(){
while(~scanf("%lld%lld%lld%lld", &x,&y,&l,&r))
{
v.clear();
for(LL i=1; i<=r; i=mul(i,x)){
for(LL j=1; i+j<=r; j=mul(j,y)){
if(l<=i+j){
v.push_back(i+j);
}
}
}
v.push_back(l-1);
v.push_back(r+1);
sort(v.begin(), v.end());
LL ans = 0;
for(int i=0; i<v.size()-1; i++){
ans = max(ans, v[i+1]-v[i]-1);
}
printf("%lld\n", ans);
}
return 0;
}
C. The Tag Game
题意:给你一个无向有根树,根节点为1,有两个人,A在节点1,B在节点X,AB轮流走,B先走,每次可以原地不动或是向相邻节点移动一次。A想最快抓到B,B想最慢被抓到,问什么时候A抓到B。
解法:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e6+7;
vector <int> v[maxn];
int n, x, dep[maxn], ans;
void dfs1(int u, int pa, int d){
dep[u] = d;
for(int son : v[u]){
if(son == pa) continue;
dfs1(son, u, d+1);
}
}
int maxdep;
void dfs2(int u, int pa){
if(dep[u]<=maxdep) return;
ans = max(ans, dep[u]);
for(int son : v[u]){
if(son == pa) continue;
dfs2(son, u);
}
}
int main()
{
scanf("%d %d", &n, &x);
for(int i=1; i<n; i++){
int x, y;
scanf("%d %d", &x, &y);
v[x].push_back(y);
v[y].push_back(x);
}
dfs1(1,1,0);
ans = 0;
maxdep = dep[x]/2;
dfs2(x,x);
printf("%d\n", ans<<1);
return 0;
}
D. Two Melodies
题意:求两个不相交的子集长度之和最大是多少,能放入同一子集的条件是首先顺序不能变,然后每一个相邻的要么相差1或者相差7的倍数。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5010;
int n,a[maxn],dp[maxn][maxn],maxmod[8],maxnum[100010];
int main()
{
while(~scanf("%d", &n)){
for(int i=1; i<=n; i++) scanf("%d", &a[i]);
memset(dp, 0, sizeof(dp));
int ans = 0;
for(int i=0;i<=n; i++){
memset(maxnum,0,sizeof(maxnum));
memset(maxmod,0,sizeof(maxmod));
for(int j=1; j<=i; j++){
maxmod[a[j]%7] = max(maxmod[a[j]%7], dp[i][j]);
maxnum[a[j]] = max(maxnum[a[j]], dp[i][j]);
}
for(int j=i+1; j<=n; j++){
dp[i][j] = max(dp[i][j], dp[i][0]+1);
dp[i][j] = max(dp[i][j], maxmod[a[j]%7]+1);
dp[i][j] = max(dp[i][j], maxnum[a[j]-1]+1);
//dp[i][j] = max(dp[i][j], maxnum[a[j]]+1);
dp[i][j] = max(dp[i][j], maxnum[a[j]+1]+1);
maxmod[a[j]%7] = max(maxmod[a[j]%7], dp[i][j]);
maxnum[a[j]] = max(maxnum[a[j]], dp[i][j]);
dp[j][i] = dp[i][j];
ans = max(ans, dp[i][j]);
}
}
printf("%d\n", ans);
}
return 0;
}
E. Army Creation
题意:n个数a[i],q次询问,n,a[i],q<=1e5。每次问[l,r]内最多可以选多少个数,满足同一个数的出现次数不超过k?
解法:设b[i] 从i开始数k个和a[i]相同的数的位置,不存在设为n+1。则[l,r] 只要b[i]>r的数都能可以被选上,转化为求区间[l,r]内有多少个数>=r。题目要求在线 所以套用主席树 ,建立权值线段树,前缀i内,第[l,r]大的数有多少个,ans=前缀r内[r,inf]个数-前缀i-1内[r,inf]个数 。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int n, q, k, a[maxn], b[maxn];
vector <int> pos[maxn];
struct node{
int l,r,sum;
}T[maxn*40];
void pre_deal(){
for(int i=n; i>=1; i--){
int sz = pos[a[i]].size();
if(sz < k) b[i] = n+1;
else b[i] = pos[a[i]][sz-k];
pos[a[i]].push_back(i);
}
}
int cnt, root[maxn];
int build(int l, int r){
int rt = ++cnt;
T[rt].sum = 0, T[rt].l = T[rt].r = 0;
if(l == r) return rt;
int mid = (l+r)/2;
T[rt].l = build(l, mid);
T[rt].r = build(mid+1, r);
return rt;
}
void update(int l, int r, int &x, int y, int pos){
T[++cnt] = T[y], T[cnt].sum++, x = cnt;
if(l == r) return;
int mid = (l+r)/2;
if(pos <= mid) update(l, mid, T[x].l, T[y].l, pos);
else update(mid+1, r, T[x].r, T[y].r, pos);
}
int query(int l, int r, int c, int L, int R){
if(L <= l && r <= R) return T[c].sum;
int mid = (l+r)/2, ans=0;
if(L <= mid) ans += query(l, mid, T[c].l, L, R);
if(mid < R) ans += query(mid+1, r, T[c].r, L, R);
return ans;
}
int main()
{
while(~scanf("%d %d", &n,&k)){
for(int i=1; i<=n; i++) scanf("%d", &a[i]);
pre_deal();
cnt = 0;
root[0] = build(1, n+1);
for(int i=1; i<=n; i++) update(1, n+1, root[i], root[i-1], b[i]);
scanf("%d", &q);
int l, r, last = 0;
while(q--){
scanf("%d %d", &l, &r);
l = (l+last)%n+1;
r = (r+last)%n+1;
if(l > r) swap(l, r);
int ans = query(1, n+1, root[r], r+1, 2e5) - query(1, n+1, root[l-1], r+1, 2e5);
printf("%d\n", ans);
last = ans;
}
return 0;
}
}
F. Bipartite Checking
蒟蒻不会啊,暂时补不了。QAQ