A - Palindrome
先跑一遍马拉车。然后线段树计算贡献。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
char ma[N], s[N];
int n, mp[N], plen[N], c[N];
vector<int> r[N];
void run(char *s, int len)
{
int l = 0;
ma[l++] = '$', ma[l++] = '#';
for(int i=0; i<len; i++) ma[l++] = s[i], ma[l++] = '#';
ma[l] = 0;
int mx = 0, id = 0;
for(int i=0; i<l; i++)
{
mp[i] = mx > i ? min(mp[2*id-i], mx-i) : 1;
while(ma[i+mp[i]]==ma[i-mp[i]]) mp[i]++;
if(i+mp[i]>mx) mx = i + mp[i], id = i;
}
for(int i=2; i<=2*len; i+=2) plen[i>>1] = mp[i]>>1;
}
void upd(int x, int v)
{
for(int i=x; i<=n; i+=(i&-i)) c[i] += v;
}
int64_t ask(int x)
{
int64_t ans = 0;
for(int i=x; i>0; i-=(i&-i)) ans += c[i];
return ans;
}
void solve()
{
scanf("%s", s);
n = strlen(s);
run(s, n);
// for(int i=1; i<=n; i++) printf("%d ", plen[i]);
// puts("");
for(int i=1; i<=n; i++) r[i].clear(), c[i] = 0;
int64_t ans = 0;
for(int i=1; i<=n; i++)
{
int l = i - plen[i] + 1;
ans += ask(n) - ask(l-1);
r[i+plen[i]-1].push_back(i);
upd(i, 1);
for(int j : r[i]) upd(j, -1);
}
printf("%lld\n", ans);
}
int main()
{
int _; scanf("%d", &_);
while(_--) solve();
return 0;
}
B - K-th Number
二分答案。check(mid)=1表示第k大的数大于等于mid的区间数的个数大于等于m。
#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x) (int)x.size()
#define cl(x) x.clear()
#define all(x) x.begin() , x.end()
#define rep(i , x , n) for(int i = x ; i <= n ; i ++)
#define per(i , n , x) for(int i = n ; i >= x ; i --)
#define mem0(x) memset(x , 0 , sizeof(x))
#define mem_1(x) memset(x , -1 , sizeof(x))
#define mem_inf(x) memset(x , 0x3f , sizeof(x))
#define debug(x) cerr << #x << " = " << x << '\n'
#define ddebug(x , y) cerr << #x << " = " << x << " " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 2e5 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ;
int n , k ;
ll m ;
int a[maxn] ;
int b[maxn] ;
bool check(int x)
{
ll res = 0 ;
rep(i , 1 , n) b[i] = (a[i] >= x) ;
int sum = b[1] ;
int j = 1 ;
rep(i , 1 , n)
{
while(sum < k && j + 1 <= n)
{
j ++ ;
sum += b[j] ;
}
//ddebug(i , j) ;
//debug(sum) ;
if(sum >= k) res += n - j + 1 ;
sum -= b[i] ;
//if(x == 2) debug(sum) ;
}
return res >= m ;
}
int main()
{
ios ;
int T ;
cin >> T ;
while(T --)
{
cin >> n >> k >> m ;
rep(i , 1 , n) cin >> a[i] ;
//debug(check(1)) ;
int l = 1 , r = 1e9 , ans = 1 ;
while(l <= r)
{
int mid = (l + r) / 2 ;
if(check(mid)) ans = mid , l = mid + 1 ;
else r = mid - 1 ;
}
cout << ans << '\n' ;
}
return 0 ;
}
C - Confliction
做法很简单,差分+分奇偶性讨论。
不过很不好写。
#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x) (int)x.size()
#define cl(x) x.clear()
#define all(x) x.begin() , x.end()
#define rep(i , x , n) for(int i = x ; i <= n ; i ++)
#define per(i , n , x) for(int i = n ; i >= x ; i --)
#define mem0(x) memset(x , 0 , sizeof(x))
#define mem_1(x) memset(x , -1 , sizeof(x))
#define mem_inf(x) memset(x , 0x3f , sizeof(x))
#define debug(x) cerr << #x << " = " << x << '\n'
#define ddebug(x , y) cerr << #x << " = " << x << " " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 4e5 + 10 ;
const int maxm = 1e7 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ;
int cnt[2] ;
struct node
{
ll x ;
ll t ;
ll l , r ;
} a[2][maxn] ;
vector<array<ll , 3> > v ;
ll ans[2] ;
struct node2
{
ll x ;
ll pos ;
bool operator < (const node2 &s) const
{
return pos < s.pos ;
}
} ;
vector<node2> p[2] ;
void add(int now , ll l , ll r , ll k)
{
if(l > r) return ;
node2 u ;
u.pos = l ;
u.x = k ;
p[now].pb(u) ;
//cout << now << ' ' << u.pos << ' ' << u.x << '\n' ;
u.pos = r + 1 ;
u.x = -k ;
p[now].pb(u) ;
//cout << now << ' ' << u.pos << ' ' << u.x << '\n' ;
}
int main()
{
ios ;
int T ;
cin >> T ;
while(T --)
{
rep(i , 0 , 1)
{
cin >> cnt[i] ;
rep(j , 1 , cnt[i])
cin >> a[i][j].x >> a[i][j].t , a[i][j].l = a[i][j - 1].r + 1 , a[i][j].r = a[i][j - 1].r + a[i][j].t ;
}
cl(v) ;
int j = 1 ;
rep(i , 1 , cnt[1])
{
v.pb({max(a[0][j].l , a[1][i].l) , min(a[0][j].r , a[1][i].r) , a[1][i].x - a[0][j].x}) ;
if(a[1][i].r < a[0][j].r) continue ;
else if(a[1][i].r == a[0][j].r) j ++ ;
else
{
j ++ ;
i -- ;
//a[1][i].l = a[0][j].r + 1 ;
}
}
//for(auto u : v) cout << u[0] << ' ' << u[1] << ' ' << u[2] << '\n' ;
ll now = 3e18 ;
cl(p[0]) ;
cl(p[1]) ;
add(now % 2 , now / 2 , now / 2 , 1) ;
for(auto u : v)
{
ll l = u[0] ;
ll r = u[1] ;
ll x = u[2] ;
ll len = r - l + 1 ;
if(x == 0) add(now % 2 , now / 2 , now / 2 , len) ;
else if(x == 1)
{
ll len1 = len / 2 ;
ll len2 = (len + 1) / 2 ;
add(now % 2 , now / 2 + 1 , now / 2 + len1 , 1) ;
add((now + 1) % 2 , (now + 1) / 2 , (now + 1) / 2 + len2 - 1 , 1) ;
}
else if(x == -1)
{
ll len1 = len / 2 ;
ll len2 = (len + 1) / 2 ;
add(now % 2 , now / 2 - len1 , now / 2 - 1 , 1) ;
add((now - 1) % 2 , (now - 1) / 2 - len2 + 1 , (now - 1) / 2 , 1) ;
}
else if(x == 2) add(now % 2 , now / 2 + 1 , now / 2 + len , 1) ;
else add(now % 2 , now / 2 - len , now / 2 - 1 , 1) ;
now += x * len ;
}
rep(i , 0 , 1) sort(all(p[i])) , ans[i] = 0 ;
rep(i , 0 , 1)
{
int siz = sz(p[i]) ;
ll res = 0 ;
rep(j , 0 , siz - 1)
{
res += p[i][j].x ;
while(j + 1 <= siz - 1 && p[i][j + 1].pos == p[i][j].pos) j ++ , res += p[i][j].x ;
ans[i] = max(ans[i] , res) ;
//debug(res) ;
}
}
cout << max(ans[0] , ans[1]) << '\n' ;
}
return 0 ;
}
D - X-Men
设距离最远的两个人的距离是d。答案是。
#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x) (int)x.size()
#define cl(x) x.clear()
#define all(x) x.begin() , x.end()
#define rep(i , x , n) for(int i = x ; i <= n ; i ++)
#define per(i , n , x) for(int i = n ; i >= x ; i --)
#define mem0(x) memset(x , 0 , sizeof(x))
#define mem_1(x) memset(x , -1 , sizeof(x))
#define mem_inf(x) memset(x , 0x3f , sizeof(x))
#define debug(x) cerr << #x << " = " << x << '\n'
#define ddebug(x , y) cerr << #x << " = " << x << " " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 1000 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ;
int n , m ;
int a[maxn] ;
int dis[maxn][maxn] ;
vector<int> g[maxn] ;
void dfs(int x , int fa , int u , int s)
{
dis[x][u] = s ;
for(auto v : g[u])
{
if(v == fa) continue ;
dfs(x , u , v , s + 1) ;
}
}
int main()
{
ios ;
int T ;
cin >> T ;
while(T --)
{
cin >> n >> m ;
rep(i , 1 , m) cin >> a[i] ;
rep(i , 1 , n) cl(g[i]) ;
rep(i , 1 , n) rep(j , 1 , n) dis[i][j] = 0 ;
rep(i , 1 , n - 1)
{
int u , v ;
cin >> u >> v ;
g[u].pb(v) , g[v].pb(u) ;
}
int ans = 0 ;
rep(i , 1 , m)
{
dfs(a[i] , a[i] , a[i] , 0) ;
rep(j , 1 , m) ans = max(ans , dis[a[i]][a[j]]) ;
}
ans /= 2 ;
cout << fixed << setprecision(2) << db(ans) << '\n' ;
}
return 0 ;
}
F - Permutation
假如n=7,那么答案就是1 5 2 6 3 7 4。
#include<bits/stdc++.h>
using namespace std ;
#define M 100005
int a[M];
int main()
{
int T;
scanf("%d",&T);
while(T--){
int n;
scanf("%d",&n);
int tot=0;
for(int i=1;i<=n;i+=2)a[i]=++tot;
for(int i=2;i<=n;i+=2)a[i]=++tot;
for(int i=1;i<=n;i++)printf("%d%c",a[i],i==n?'\n':' ');
}
}
H - A Simple Stone Game
设石子和是sum。对sum进行质因子分解,枚举质因子作为x,然后贪心check即可。
#include<bits/stdc++.h>
using namespace std ;
#define M 100005
#define ll long long
int a[M],b[M],cnt[M],pri[M];
void init(){
for(int i=2;i<=M-5;i++){
if(!pri[i])pri[++pri[0]]=i;
for(int j=i+i;j<=M-5;j+=i){
pri[j]=1;
}
}
}
void solve(){
int n;ll sum=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]),sum+=a[i];
ll ans=1e18;
// printf("%d\n",pri[1]);
sort(a+1,a+n+1);
if(n==1)puts("0");
else {
for(int t=1;t<=pri[0];t++){
if(sum%pri[t]==0){
// printf("%d\n",pri[t]);
int m=0;
for(int i=0;i<pri[t];i++)cnt[i]=0;
for(int i=1;i<=n;i++)cnt[a[i]%pri[t]]++;
for(int i=1;i<pri[t];i++)
for(int j=1;j<=cnt[i];j++)b[++m]=i;
ll s=0,tmp=0;
// printf("%d\n",m);
for(int i=1;i<=m;i++)s+=b[i];
for(int i=1;i<=m;i++){
tmp+=b[i];
if(1ll*(m-i)*pri[t]==s)ans=min(ans,tmp);
}
while(sum%pri[t]==0)sum/=pri[t];
}
}
if(sum!=1){
ll s=0,tmp=0;
for(int i=1;i<=n;i++)s+=a[i];
for(int i=1;i<=n;i++){
tmp+=a[i];
if(1ll*(n-i)*sum==s)ans=min(ans,tmp);
}
}
printf("%lld\n",ans);
}
}
int main(){
int T;
scanf("%d",&T);
init();
while(T--)solve();
}
J - Interview
待补题。没想清楚推理过程。找zh商量一波。
K - Server
从题目给的公式看出是裸的01分数规划。
判断是否可以覆盖[1,t]是按区间左端点排序后线段树优化dp。
ps:hdu的cin相当慢。这道题如果用bit会快很多,如果用线段树差点就TLE,不过卡这个常数我觉得很无聊。
#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x) (int)x.size()
#define cl(x) x.clear()
#define all(x) x.begin() , x.end()
#define rep(i , x , n) for(int i = x ; i <= n ; i ++)
#define per(i , n , x) for(int i = n ; i >= x ; i --)
#define mem0(x) memset(x , 0 , sizeof(x))
#define mem_1(x) memset(x , -1 , sizeof(x))
#define mem_inf(x) memset(x , 0x3f , sizeof(x))
#define debug(x) cerr << #x << " = " << x << '\n'
#define ddebug(x , y) cerr << #x << " = " << x << " " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 2e5 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ;
int n , t ;
struct node
{
int s , t ;
db a , b ;
bool flag ;
bool operator < (const node &x) const
{
return s < x.s ;
}
} a[maxn] ;
db mn[maxn << 2] ;
int ls(int x)
{
return x << 1 ;
}
int rs(int x)
{
return x << 1 | 1 ;
}
void build(int id , int l , int r)
{
if(l == r){mn[id] = 1e9 ; return ;}
int mid = (l + r) >> 1 ;
build(ls(id) , l , mid) ;
build(rs(id) , mid + 1 , r) ;
mn[id] = min(mn[ls(id)] , mn[rs(id)]) ;
}
void update(int id , int l , int r , int x , db y)
{
int mid = (l + r) / 2 ;
if(l == r && l == x){mn[id] = min(mn[id] , y) ; return ;}
if(x <= mid) update(ls(id) , l , mid , x , y) ;
else update(rs(id) , mid + 1 , r , x , y) ;
mn[id] = min(mn[ls(id)] , mn[rs(id)]) ;
}
db query(int id , int l , int r , int x , int y)
{
db ans = 1e9 ;
int mid = (l + r) / 2 ;
if(y < x) return 0 ; //不合法的询问
if(x <= l && r <= y) return mn[id] ;
if(x <= mid) ans = min(ans , query(ls(id) , l , mid , x , y)) ;
if(y > mid) ans = min(ans , query(rs(id) , mid + 1 , r , x , y)) ;
return ans ;
}
db cal(int i)
{
if(a[i].s == 1) return 0 ;
else return query(1 , 1 , t , a[i].s - 1 , t) ;
}
bool ok(db x)
{
db sum = 0 ;
build(1 , 1 , t) ;
rep(i , 1 , n) a[i].flag = (a[i].b * x - a[i].a > 0) ;
rep(i , 1 , n)
if(a[i].flag) update(1 , 1 , t , a[i].t , cal(i)) , sum += a[i].b * x - a[i].a ;
else update(1 , 1 , t , a[i].t , cal(i) + (a[i].a - a[i].b * x)) ;
return sum >= query(1 , 1 , t , t , t) ;
}
int main()
{
int T ;
scanf("%d" , &T) ;
while(T --)
{
scanf("%d%d" , &n , &t) ;
rep(i , 1 , n) scanf("%d%d%lf%lf" , &a[i].s , &a[i].t , &a[i].a , &a[i].b) ;
sort(a + 1 , a + n + 1) ;
db l = 0 , r = 1000 ;
db ans = r ;
while(r - l > 1e-4)
{
db mid = (l + r) / 2 ;
if(ok(mid)) ans = mid , r = mid ;
else l = mid ;
}
printf("%.3f\n" , ans) ;
}
return 0 ;
}
L - Color a Tree
二分答案。对于子树外的大于等于号变成子树内的小于等于号,然后树形dp一下。
#include<bits/stdc++.h>
using namespace std;
#define M 100005
#define ll long long
struct Edge{
int to,nxt;
}edge[M<<1];
int head[M],tot;
int sz[M],tmp[M];
ll mx[M],mi[M];
void Add(int a,int b){
edge[tot].to=b;edge[tot].nxt=head[a];head[a]=tot++;
}
void ldfs(int x,int pre){
sz[x]=1;
for(int i=head[x];~i;i=edge[i].nxt){
int y=edge[i].to;
if(y==pre)continue;
ldfs(y,x);
sz[x]+=sz[y];
}
}
ll dfs(int x,int pre){
ll summi=0,summx=0;
for(int i=head[x];~i;i=edge[i].nxt){
int y=edge[i].to;
if(y==pre)continue;
ll dpy=dfs(y,x);
if(dpy==-1ll)return -1ll;
summx+=mx[y];
summi+=dpy;
}
if(sz[x]!=1)mx[x]=min(summx+1,mx[x]);
// printf("mx[%d]=%d mi=%d\n",x,mx[x],max(mi[x],sum));
// printf("%d %d %d\n",x,mx[x],mi[x]);
if(max(summi,mi[x])>mx[x])return -1ll;
return max(summi,mi[x]);
}
bool check(int k,int n){
for(int i=1;i<=n;i++){
mx[i]=min(k-tmp[i],sz[i]);
if(mx[i]<0)return 0;
}
ll Dfs=dfs(1,-1);
if(Dfs==-1)return 0;
if(Dfs>k||mx[1]<k)return 0;
return 1;
}
void solve(){
int n;
scanf("%d",&n);
tot=0;
for(int i=1;i<=n;i++)head[i]=-1,mi[i]=tmp[i]=0;
for(int i=1;i<n;i++){
int a,b;
scanf("%d %d",&a,&b);
Add(a,b);
Add(b,a);
}
int A,B;
scanf("%d",&A);
ldfs(1,-1);
bool f=1;
for(int i=1;i<=A;i++){
int x,y;
scanf("%d %d",&x,&y);
mi[x]=max(mi[x],1ll*y);
if(mi[x]>sz[x])f=0;
}
scanf("%d",&B);
for(int i=1;i<=B;i++){
int x,y;
scanf("%d %d",&x,&y);
tmp[x]=max(tmp[x],y);
if(tmp[x]>n-sz[x])f=0;
}
if(!f){
puts("-1");
return;
}
int l=0,r=n,ans=-1;
while(l<=r){
int mid=l+r>>1;
if(check(mid,n)){
ans=mid;
r=mid-1;
}
else l=mid+1;
}
printf("%d\n",ans);
}
int main(){
int T;
scanf("%d",&T);
while(T--)solve();
return 0;
}
M - Geometry Problem
每次随机三个点确定一个圆。注意特判。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
using db = double;
const db eps = 1e-4;
db sqr(db x) { return x*x; }
int sgn(db x) { return x<-eps ? -1 : x>eps; }
int n;
struct P
{
db x, y;
P(){}
P(db _x, db _y) : x(_x), y(_y) {}
void in() { scanf("%lf%lf", &x, &y); }
db dis(P p) { return sqrt(sqr(x-p.x) + sqr(y-p.y)); }
P operator + (P p) { return P(x+p.x, y+p.y); }
P operator - (P p) { return P(x-p.x, y-p.y); }
P operator / (db k) { return P(x/k, y/k); }
P rotright() { return P(y, -x); }
db operator ^ (P p) { return x*p.y - y*p.x; }
}p[N];
struct L
{
P s, e;
L(){}
L(P _s, P _e) { s = _s, e = _e; }
P crosspoint(L v)
{
db a1 = (v.e - v.s) ^ (s - v.s);
db a2 = (v.e - v.s) ^ (e - v.s);
return P((s.x*a2-e.x*a1)/(a2-a1), (s.y*a2-e.y*a1)/(a2-a1));
}
};
struct C
{
P p;
db r;
C(){}
C(P a, P b, P c)
{
L u = L((a+b)/2, ((a+b)/2)+((b-a).rotright()));
L v = L((b+c)/2, ((b+c)/2)+((c-b).rotright()));
p = u.crosspoint(v);
r = p.dis(a);
}
};
void solve()
{
scanf("%d", &n);
for(int i=0; i<n; i++) p[i].in();
if(n==1)
{
printf("%.5f %.5f %.5f\n", p[0].x-1, p[0].y, 1.0);
return;
}
else if(n<=4)
{
P o = (p[0]+p[1])/2;
printf("%.5f %.5f %.5f\n", o.x, o.y, o.dis(p[0]));
return;
}
while(true)
{
int a = rand()%n, b = rand()%n, c = rand()%n;
if(a==b || a==c || b==c) continue;
if(sgn((p[a]-p[b])^(p[a]-p[c]))==0) continue;
// printf("%d %d %d\n", a, b, c);
C o(p[a], p[b], p[c]);
int cnt = 0;
for(int i=0; i<n; i++) if(sgn(p[i].dis(o.p)-o.r)==0) cnt++;
if(cnt>=n/2)
{
//for(int i=0; i<n; i++) if(sgn(p[i].dis(o.p)-o.r)==0) cout << i << '\n';
printf("%.5f %.5f %.5f\n", o.p.x, o.p.y, o.r);
return;
}
}
}
int main()
{
srand(int(time(0)));
int _; scanf("%d", &_);
while(_--) solve();
return 0;
}