XVII Open Cup named after E.V. Pankratiev. GP of Siberia, Division 1
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; }