1. Ski race
枚举枚举倍数判断即可。时间复杂度$O(n\log m)$。
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,i,j,ans,flag,q[111111],a[111111];
bool v[11111111];
int main(){
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
scanf("%d",&n);
m=10000000;
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
v[a[i]]=1;
}
for(i=1;i<=n;i++){
flag=1;
for(j=a[i]*2;j<=m;j+=a[i])if(v[j]){
flag=0;
break;
}
if(flag)q[++ans]=a[i];
}
sort(q+1,q+ans+1);
for(i=1;i<=ans;i++)printf("%d ",q[i]);
}
2. Chairs
DP求出每个点开始走最多能碰到几个椅子,时间复杂度$O(nm)$。
#include <bits/stdc++.h>
using namespace std ; const int MAXN = 105 ;
const int INF = 0x3f3f3f3f ; int G[MAXN][MAXN] , dp[MAXN][MAXN] , p[MAXN][MAXN] ;
int n , m , k ; void put ( int x , int y ) {
if ( x == n && y == m ) return ;
//printf ( "%d %d\n" , x , y ) ;
if ( p[x][y] == 0 ) {
printf ( "D" ) ;
put ( x + 1 , y ) ;
} else {
printf ( "R" ) ;
put ( x , y + 1 ) ;
}
} void solve () {
memset ( dp , -INF , sizeof dp ) ;
memset ( G , 0 , sizeof G ) ;
memset ( p , 0 , sizeof p ) ;
for ( int i = 0 ; i < k ; ++ i ) {
int x , y ;
scanf ( "%d%d" , &x , &y ) ;
G[x][y] ++ ;
}
dp[n][m] = G[n][m] ;
for ( int i = n ; i >= 1 ; -- i ) {
for ( int j = m ; j >= 1 ; -- j ) {
if ( i == n && j == m ) continue ;
if ( dp[i][j + 1] <= dp[i + 1][j] ) {
dp[i][j] = dp[i + 1][j] + G[i][j] ;
p[i][j] = 0 ;
} else {
dp[i][j] = dp[i][j + 1] + G[i][j] ;
p[i][j] = 1 ;
}
}
}
if ( dp[1][1] != k ) printf ( "Impossible" ) ;
else put ( 1 , 1 ) ;
puts ( "" ) ;
} int main () {
freopen ( "input.txt" , "r" , stdin ) ;
freopen ( "output.txt" , "w" , stdout ) ;
while ( ~scanf ( "%d%d%d" , &n , &m , &k ) ) solve () ;
return 0 ;
}
3. Triangle
留坑。
4. Wires
将所有点对$(a,b)$按$a$排序,那么内外都要满足$b$递增。
设$f[i][j][k]$表示考虑前$i$个点,最后一个与$i$不在一个序列的数的$b$是$j$,且$i$属于序列$k$时的最小总代价。
那么状态的保存以及转移均可以用线段树实现,时间复杂度$O(n\log n)$。
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=100010,M=262150;
const double inf=1e30;
int A,B,n,i,b[N];
double v0[N],v1[N];
struct P{int l,r;}a[N];
inline bool cmp(const P&a,const P&b){return a.l<b.l;}
inline int lower(int x){
int l=1,r=n,mid,t;
while(l<=r)if(b[mid=(l+r)>>1]<=x)l=(t=mid)+1;else r=mid-1;
return t;
}
struct DS{
double v[M],ta[M],tc[M];
void build(int x,int a,int b){
v[x]=inf;
tc[x]=-9;
if(a==b)return;
int mid=(a+b)>>1;
build(x<<1,a,mid);
build(x<<1|1,mid+1,b);
}
inline void add1(int x,double p){
v[x]+=p;
if(tc[x]>-1)tc[x]+=p;else ta[x]+=p;
}
inline void col1(int x,double p){
v[x]=p;
tc[x]=p;
ta[x]=0;
}
inline void pb(int x){
if(ta[x]>0.5){
add1(x<<1,ta[x]);
add1(x<<1|1,ta[x]);
ta[x]=0;
}
if(tc[x]>-1){
col1(x<<1,tc[x]);
col1(x<<1|1,tc[x]);
tc[x]=-9;
}
}
inline void up(int x){
v[x]=min(v[x<<1],v[x<<1|1]);
}
void change(int x,int a,int b,int c,double p){
if(a==b){
v[x]=min(v[x],p);
return;
}
pb(x);
int mid=(a+b)>>1;
if(c<=mid)change(x<<1,a,mid,c,p);
else change(x<<1|1,mid+1,b,c,p);
up(x);
}
double ask(int x,int a,int b,int c,int d){
if(c<=a&&b<=d)return v[x];
pb(x);
int mid=(a+b)>>1;
double t=inf;
if(c<=mid)t=ask(x<<1,a,mid,c,d);
if(d>mid)t=min(t,ask(x<<1|1,mid+1,b,c,d));
return t;
}
}f,g;
int main(){
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
scanf("%d%d%d",&A,&B,&n);
for(i=1;i<=n;i++)scanf("%d",&a[i].l);
for(i=1;i<=n;i++)scanf("%d",&a[i].r),b[i]=a[i].r;
sort(a+1,a+n+1,cmp);
sort(b+1,b+n+1);
for(i=1;i<=n;i++){
v0[i]=sqrt(1.0*(a[i].l-a[i].r)*(a[i].l-a[i].r)+1.0*B*B);
v1[i]=min(a[i].l+a[i].r,A+A-a[i].l-a[i].r)+B;
a[i].r=lower(a[i].r);
}
f.build(1,0,n);
g.build(1,0,n);
f.change(1,0,n,0,v0[1]);
g.change(1,0,n,0,v1[1]);
for(i=1;i<n;i++){
double x=f.ask(1,0,n,0,a[i+1].r-1),
y=g.ask(1,0,n,0,a[i+1].r-1);
if(a[i+1].r<a[i].r){
f.col1(1,inf);
g.col1(1,inf);
}
f.change(1,0,n,a[i].r,y);
g.change(1,0,n,a[i].r,x);
f.add1(1,v0[i+1]);
g.add1(1,v1[i+1]);
}
double ans=min(f.v[1],g.v[1]);
if(ans>1e28)puts("-1");else printf("%.15f",ans);
}
5. Voting
枚举票数然后建图求最小费用最大流。
#include <bits/stdc++.h>
using namespace std ; typedef long long LL ; const int MAXN = 1005 ;
const int MAXE = 1000005 ;
const LL INF = 1e18 ;
const LL L = 1e15 ; struct Edge {
int v , c , n ;
LL w ;
Edge () {}
Edge ( int v , int c , LL w , int n ) : v ( v ) , c ( c ) , w ( w ) , n ( n ) {}
} ; Edge E[MAXE] ;
int H[MAXN] , cntE ;
LL d[MAXN] , cost ;
int vis[MAXN] , cur[MAXN] ;
int Q[MAXN] , head , tail ;
int n , K , T ;
int s , t ;
int flow ;
int G[MAXN][15] ;
int res[MAXN] ; void init () {
cntE = 0 ;
memset ( H , -1 , sizeof H ) ;
} void addedge ( int u , int v , int c , LL w ) {
E[cntE] = Edge ( v , c , w , H[u] ) ;
H[u] = cntE ++ ;
E[cntE] = Edge ( u , 0 , -w , H[v] ) ;
H[v] = cntE ++ ;
} int spfa () {
for ( int i = 0 ; i < MAXN ; ++ i ) {
d[i] = INF ;
vis[i] = 0 ;
}
head = tail = 0 ;
Q[tail ++] = s ;
d[s] = 0 ;
cur[s] = -1 ;
while ( head != tail ) {
int u = Q[head ++] ;
if ( head == MAXN ) head = 0 ;
vis[u] = 0 ;
for ( int i = H[u] ; ~i ; i = E[i].n ) {
int v = E[i].v ;
if ( E[i].c && d[v] > d[u] + E[i].w ) {
d[v] = d[u] + E[i].w ;
cur[v] = i ;
if ( !vis[v] ) {
vis[v] = 1 ;
Q[tail ++] = v ;
if ( tail == MAXN ) tail = 0 ;
}
}
}
}
if ( d[t] == INF ) return 0 ;
cost += d[t] ;
flow ++ ;
for ( int i = cur[t] ; ~i ; i = cur[E[i ^ 1].v] ) {
E[i].c -- ;
E[i ^ 1].c ++ ;
}
return 1 ;
} void mcmf () {
cost = flow = 0 ;
while ( spfa () ) ;
} int check ( int x ) {
for ( int i = H[T] ; ~i ; i = E[i].n ) {
int v = E[i].v ;
if ( v != t ) continue ;
return E[i ^ 1].c == x ;
}
} void getans () {
for ( int i = 1 ; i <= n ; ++ i ) {
for ( int j = H[K + 1 + i] ; ~j ; j = E[j].n ) {
int v = E[j].v ;
if ( v == s ) continue ;
if ( E[j].c == 0 ) {
res[i] = E[j].v ;
break ;
}
}
}
} void solve () {
for ( int i = 1 ; i <= n ; ++ i ) {
for ( int j = 1 ; j <= K + 1 ; ++ j ) {
scanf ( "%d" , &G[i][j] ) ;
}
}
LL ans = INF ;
if ( K == 1 ) {
ans = 0 ;
for ( int i = 1 ; i <= n ; ++ i ) {
if ( G[i][1] < G[i][2] ) {
ans += G[i][1] ;
res[i] = 1 ;
} else {
ans += G[i][2] ;
res[i] = 2 ;
}
}
printf ( "%lld\n" , ans ) ;
for ( int i = 1 ; i <= n ; ++ i ) {
i > 1 && putchar ( ' ' ) ;
printf ( "%d" , res[i] ) ;
}
puts ( "" ) ;
return ;
}
s = 0 , t = K + 1 + n + 1 ;
for ( int i = 1 ; i <= n ; ++ i ) {
init () ;
for ( int j = 1 ; j <= n ; ++ j ) {
addedge ( s , K + 1 + j , 1 , 0 ) ;
}
for ( int j = 1 ; j <= K ; ++ j ) {
if ( j != T ) addedge ( j , t , i - 1 , 0 ) ;
else addedge ( j , t , i , -L ) ;
}
addedge ( K + 1 , t , 10000 , 0 ) ;
for ( int j = 1 ; j <= n ; ++ j ) {
for ( int k = 1 ; k <= K + 1 ; ++ k ) {
addedge ( K + 1 + j , k , 1 , G[j][k] ) ;
}
}
mcmf () ;
//if ( !check ( i ) ) continue ;
cost += i * L ;
cost %= L ;
if ( cost < ans ) {
ans = cost ;
getans () ;
}
}
printf ( "%lld\n" , ans ) ;
for ( int i = 1 ; i <= n ; ++ i ) {
i > 1 && putchar ( ' ' ) ;
printf ( "%d" , res[i] ) ;
}
puts ( "" ) ;
} int main () {
freopen ( "input.txt" , "r" , stdin ) ;
freopen ( "output.txt" , "w" , stdout ) ;
while ( ~scanf ( "%d%d%d" , &n , &K , &T ) ) solve () ;
return 0 ;
}
6. Finite automaton
定义状态$i$表示当前读入的数字串模$M$为$i$的状态,然后最小化这个DFA即可。
7. Scene management
留坑。
8. A system of balance scales
树状数组维护DFS序。
#include<cstdio>
typedef long long ll;
const int N=200010;
int n,m,i,w[N],l[N],r[N],st[N],en[N],dfn,len[N],op,x,y;
ll bit[N];
inline void add(int x,int y){
if(!x)return;
for(;x<=dfn;x+=x&-x)bit[x]+=y;
}
inline ll ask(int x){
ll t=0;
for(;x;x-=x&-x)t+=bit[x];
return t;
}
void dfs(int x){
st[x]=++dfn;
if(l[x])dfs(l[x]);
if(r[x])dfs(r[x]);
en[x]=dfn;
}
int main(){ freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
scanf("%d%d",&n,&m);
for(i=1;i<=n+1;i++){//id=n+i
scanf("%d",&w[i]);
}
for(i=1;i<=n;i++){
scanf("%d%d%d",&len[i],&l[i],&r[i]);
if(l[i]<0)l[i]=n-l[i];
if(r[i]<0)r[i]=n-r[i];
}
dfs(1);
for(i=1;i<=n+1;i++)add(st[n+i],w[i]);
while(m--){
scanf("%d%d",&op,&x);
if(op==1){
scanf("%d",&y);
add(st[n+x],y-w[x]);
w[x]=y;
}else{
ll A=ask(en[l[x]])-ask(st[l[x]]-1);
ll B=ask(en[r[x]])-ask(st[r[x]]-1);
double ans=1.0*B*len[x]/(A+B);
printf("%.15f\n",ans);
}
}
}
9. Karmon be ill
按题意模拟即可。
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<time.h>
#include<assert.h>
#include<iostream>
using namespace std;
typedef long long LL;
typedef pair<int,int>pi;
int n,k;
multiset<int>s1,s2;
bool go1(multiset<int>&S,int x,int &sum){
if(S.size()<k){
S.insert(x);
sum+=x;
return 1;
}
if(*S.begin()<x){
int tmp=*S.begin();
sum-=tmp;
S.erase(S.begin());
s2.insert(tmp);
S.insert(x);
sum+=x;
return 1;
}
return 0;
}
int main(){
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
scanf("%d%d",&n,&k);
int sum1=0,sum2=0;
for(int i=1;i<=n;i++){
int x;scanf("%d",&x);
if(!go1(s1,x,sum1))s2.insert(x);
if(s1.size()>=k){
printf("%d%c",sum1,i==n?'\n':' ');
}
}
return 0;
}
10. Battle City Online
留坑。
11. Test generation
考虑模$P$意义下的Hash,按Hash值排序后双指针即可。
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<time.h>
#include<assert.h>
#include<iostream>
using namespace std;
typedef long long LL;
typedef pair<int,int>pi;
char s[100020];
int P,rev,ls;
int pw[100020];
int h[100020];
pi a[100020],b[100020];
map<int,int>Loc,Mp;
int powmod(int x,int y,int mod){
int ret=1;
while(y){
if(y&1)ret=1LL*ret*x%mod;
y>>=1;
x=1LL*x*x%mod;
}
return ret;
}
int main(){
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
scanf("%s",s+1);
ls=strlen(s+1);
int _;scanf("%d%d",&_,&P);
rev=powmod(10,P-2,P);
pw[0]=1;
for(int i=1;i<=ls;i++)pw[i]=1LL*pw[i-1]*rev%P;
while(_--){
int x;scanf("%d",&x);
int cur=0;
int resl=-1,resr=-1;
LL ans=0;
b[0]=pi(0,0);
for(int i=1;i<=ls;i++){
cur=(1LL*cur*10+s[i]-'0')%P;
int ned=(cur-x+P)%P;
ned=1LL*ned*pw[i]%P;
a[i-1]=pi(ned,i);
b[i]=pi(1LL*cur*pw[i]%P,i);
}
sort(a,a+ls);
sort(b,b+ls);
for(int i=0,j=0;i<ls&&j<ls;){
if(a[i].first==b[j].first){
int t1,t2;
for(t1=i,t2=j;t1<ls&&a[t1].first==a[i].first;t1++){
while(t2<ls&&(b[t2].first==b[j].first)&&(b[t2].second<a[t1].second))t2++;
if(t2>j){
resl=b[j].second;
resr=a[t1].second;
ans+=t2-j;
}
}
i=t1;
}
else {
if(a[i].first>b[j].first)j++;
else i++;
}
}
if(resl<0)puts("0 0 0");
else printf("%lld %d %d\n",ans,resl+1,resr);
}
return 0;
}