XIV Open Cup named after E.V. Pankratiev. GP of SPb

A. Bracket Expression

直接按题意模拟即可。

时间复杂度$O(n)$。

#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;
const int Maxn=55;
char s[Maxn];
int ls;
LL sta[Maxn];
int top=0;
int main(){
freopen("bracket-expression.in","r",stdin);
freopen("bracket-expression.out","w",stdout);
fgets(s,sizeof s,stdin);
for(int i=0;(s[i]=='(')||(s[i]==')');i++){//-1,-2
if(s[i]=='(')sta[top++]=-1;
else{
LL cur=1;
while(top&&sta[top-1]!=-1){
cur=cur*sta[top-1];
top--;
}
sta[top-1]=cur+1;
}
}
LL ret=1;
while(top)ret=1LL*ret*sta[top-1],top--;
printf("%lld\n",ret);
return 0;
}

  

B. Checkers

暴力搜索所有对战情况,然后模拟。

时间复杂度$O(2^nk)$。

#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;
string s[22];
int ans=0;
int jud(vector<int>&V,string &s){
for(int i=V.size()-1,j=s.size()-1;i>=0&&j>=0;i--,j--){
if(V[i]==(s[j]=='W'))continue;
if(V[i])return 0;
else return 1;
}
return 1;
}
void dfs(int cur,int op,int win,vector<int>V){
if(cur>=k){
ans=max(ans,win);
return;
}
for(int i=1;i+cur<=k&&i<=2;i++){
string tmp=s[op];
vector<int>nxt=V;
int tmpwin=win;
for(int j=0;j<i;j++){
int res=jud(nxt,s[op]);
nxt.push_back(res);
if(res)tmpwin++;
s[op].push_back(res?'B':'W');//res==1:w
}
dfs(cur+i,(op+1)%n,tmpwin,nxt);
s[op]=tmp;
}
}
int main(){
freopen("checkers.in","r",stdin);
freopen("checkers.out","w",stdout);
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++)cin>>s[i];
vector<int>V;
dfs(0,0,0,V);
printf("%d\n",ans);
return 0;
}

  

C. Convex and Compact

枚举起点,设$f[i][j][k]$表示当前凸包转到了$i$点,凸包上和内部有$j$个点,凸包上有$k$个点时凸包的最小周长,然后DP即可。

时间复杂度$O(n^4k)$。

#include <bits/stdc++.h>
using namespace std ; typedef long long LL ;
typedef pair < int , int > pii ; #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 65 ;
const double INF = 1e60 ;
const double eps = 1e-8 ;
const double pi = acos ( -1.0 ) ; int dcmp ( double x ) {
return ( x > eps ) - ( x < -eps ) ;
} struct Point {
int x , y ;
Point () {}
Point ( int x , int y ) : x ( x ) , y ( y ) {}
bool operator < ( const Point& a ) const {
return x != a.x ? x < a.x : y < a.y ;
}
Point operator + ( const Point& a ) const {
return Point ( x + a.x , y + a.y ) ;
}
Point operator - ( const Point& a ) const {
return Point ( x - a.x , y - a.y ) ;
}
int operator * ( const Point& a ) const {
return x * a.y - y * a.x ;
}
double angle () {
return atan2 ( y , x ) ;
}
double len () {
return sqrt ( 0.0 + x * x + y * y ) ;
}
} ; struct Node {
double r ;
int idx ;
bool operator < ( const Node& a ) const {
return r < a.r ;
}
} ; struct Pre {
int x , y , z ;
Pre () {}
Pre ( int x , int y , int z ) : x ( x ) , y ( y ) , z ( z ) {}
} ; Node a[MAXN] ;
Point p[MAXN] ;
int n , K ;
int in[MAXN][MAXN] ;
Pre pre[MAXN][MAXN][17] ;
double len2[MAXN][MAXN] ;
double dp[MAXN][MAXN][17] ;
double ans ;
int S[MAXN] , top ;
int vis[MAXN] ;
int id[MAXN] ; int cmp ( const int&a , const int& b ) {
return p[a].x != p[b].x ? p[a].x < p[b].x : p[a].y < p[b].y ;
} bool PointInTri ( int i , int j , int k , int l ) {
LL a = ( p[i] - p[l] ) * ( p[j] - p[l] ) ;
LL b = ( p[j] - p[l] ) * ( p[k] - p[l] ) ;
LL c = ( p[k] - p[l] ) * ( p[i] - p[l] ) ;
return a * b > 0 && b * c > 0 && c * a > 0 ;
} void insert ( int x , int y , int z ) {
Pre t = pre[x][y][z] ;
if ( t.x ) insert ( t.x , t.y , t.z ) ;
S[top ++] = a[x].idx ;
} void calc ( int m ) {
for ( int i = 0 ; i <= m ; ++ i ) {
for ( int j = 0 ; j <= m + 1 ; ++ j ) {
for ( int k = 0 ; k <= K ; ++ k ) {
dp[i][j][k] = INF ;
pre[i][j][k] = Pre ( 0 , 0 , 0 ) ;
}
}
for ( int j = 0 ; j <= m ; ++ j ) {
len2[i][j] = ( p[a[i].idx] - p[a[j].idx] ).len () ;
}
}
for ( int i = 1 ; i <= m ; ++ i ) {
for ( int j = i + 1 ; j <= m ; ++ j ) {
in[i][j] = 3 ;
for ( int l = 1 ; l <= m ; ++ l ) if ( l != i && l != j ) {
if ( PointInTri ( a[0].idx , a[i].idx , a[j].idx , a[l].idx ) ) {
in[i][j] ++ ;
}
}
}
}
for ( int i = 1 ; i <= m ; ++ i ) {
dp[i][2][2] = len2[0][i] * 2 ;
pre[i][2][2] = Pre ( 0 , 0 , 0 ) ;
for ( int j = 2 ; j <= m ; ++ j ) {
for ( int k = 3 ; k <= min ( i + 1 , K ) ; ++ k ) {
for ( int l = 1 ; l < i ; ++ l ) if ( dp[l][j][k - 1] < 1e50 ) {
int num = j + in[l][i] - 2 ;
double tmp = dp[l][j][k - 1] - len2[0][l] + len2[0][i] + len2[i][l] ;
if ( dp[i][num][k] > tmp ) {
dp[i][num][k] = tmp ;
//printf ( "%d %d %d %.5f\n" , i , num , k , dp[i][num][k] ) ;
pre[i][num][k] = Pre ( l , j , k - 1 ) ;
}
}
}
}
}
int x = -1 , y , z ;
for ( int i = 1 ; i <= m ; ++ i ) {
for ( int j = K ; j <= m + 1 ; ++ j ) {
for ( int k = 3 ; k <= K ; ++ k ) if ( dp[i][j][k] < 1e50 ) {
//printf ( "dp[%d][%d][%d] = %.5f\n" , i , j , k , dp[i][j][k] ) ;
if ( dcmp ( dp[i][j][k] - ans ) < 0 ) {
ans = dp[i][j][k] ;
x = i ;
y = j ;
z = k ;
}
}
}
}
if ( ~x ) {
top = 0 ;
insert ( x , y , z ) ;
S[top ++] = a[0].idx ;
}
} int check ( int x ) {
LL f = ( p[x] - p[S[0]] ) * ( p[x] - p[S[1]] ) ;
for ( int i = 0 ; i < top ; ++ i ) {
LL ff = ( p[x] - p[S[i]] ) * ( p[x] - p[S[( i + 1 ) % top]] ) ;
if ( f * ff < 0 ) return 0 ;
}
return 1 ;
} void solve () {
ans = INF ;
for ( int i = 1 ; i <= n ; ++ i ) {
scanf ( "%d%d" , &p[i].x , &p[i].y ) ;
}
if ( K == 1 ) {
printf ( "%d\n" , 0 ) ;
printf ( "%d\n" , 1 ) ;
return ;
}
if ( K == 2 ) {
int x , y ;
for ( int i = 1 ; i <= n ; ++ i ) {
for ( int j = i + 1 ; j <= n ; ++ j ) {
double tmp = ( p[i] - p[j] ).len () ;
if ( tmp < ans ) {
ans = tmp ;
x = i ;
y = j ;
}
}
}
printf ( "%.8f\n" , ans ) ;
printf ( "%d %d\n" , x , y ) ;
return ;
}
for ( int i = 1 ; i <= n ; ++ i ) {
id[i] = i ;
}
sort ( id + 1 , id + n + 1 , cmp ) ;
a[0].r = -INF ;
for ( int i = 1 ; i <= n ; ++ i ) {
int m = 0 ;
for ( int j = i + 1 ; j <= n ; ++ j ) {
++ m ;
a[m].idx = id[j] ;
a[m].r = ( p[id[j]] - p[id[i]] ).angle () ;
//if ( dcmp ( a[j].r ) < 0 ) a[j].r = 2 * pi + a[j].r ;
}
a[0].idx = id[i] ;
sort ( a + 1 , a + m + 1 ) ;
if ( m + 1 >= K ) calc ( m ) ;
}
printf ( "%.8f\n" , ans ) ;
int flag = 0 ;
clr ( vis , 0 ) ;
for ( int i = 0 ; i < top ; ++ i ) {
if ( flag ) printf ( " " ) ;
flag = 1 ;
printf ( "%d" , S[i] ) ;
vis[S[i]] = 1 ;
}
for ( int i = top + 1 ; i <= K ; ++ i ) {
for ( int j = 1 ; j <= n ; ++ j ) if ( !vis[j] ) {
if ( check ( j ) ) {
printf ( " %d" , j ) ;
vis[j] = 1 ;
break ;
}
}
}
puts ( "" ) ;
} int main () {
freopen ( "convexset.in" , "r" , stdin ) ;
freopen ( "convexset.out" , "w" , stdout ) ;
while ( ~scanf ( "%d%d" , &n , &K ) ) solve () ;
return 0 ;
}

  

D. Forbidden Words

留坑。

E. Four Prime Numbers

设$f[i]$表示用两个质数能拼出$i$的方案数,可以通过暴力枚举两个质数求出,则$ans=\sum f[i]f[n-i]$。

时间复杂度$O(\frac{n^2}{\ln^2n})$。

#include<cstdio>
const int N=100010;
int n,i,j,tot,v[N],p[N],f[N];long long ans;
int main(){
freopen("fourprimes.in","r",stdin);
freopen("fourprimes.out","w",stdout);
scanf("%d",&n);
for(i=2;i<=n;i++){
if(!v[i])p[tot++]=i;
for(j=0;j<tot;j++){
if(i*p[j]>n)break;
v[i*p[j]]=1;
if(i%p[j]==0)break;
}
}
for(i=0;i<tot;i++){
if(p[i]+p[i]<=n)f[p[i]+p[i]]++;
for(j=0;j<i;j++){
if(p[i]+p[j]>n)break;
f[p[i]+p[j]]+=2;
}
}
for(i=1;i<=n;i++)ans+=1LL*f[i]*f[n-i];
printf("%lld",ans);
return 0;
}

  

F. Set Intersection

随机化找出规律:$ans=\lfloor\frac{LM}{N}\rfloor$。

#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 LIM=1000;
int a[1000020],b[1000020];
int n,l,m;
int c[1000020],ans[1000020];
int main(){
freopen("intset.in","r",stdin);
freopen("intset.out","w",stdout);
while(scanf("%d%d%d",&n,&l,&m)!=EOF){
long long now=1LL*m*l/n;
printf("%lld",now);
/* for(int i=0;i<n;i++)b[i]=i;
for(int i=0;i<LIM;i++){
random_shuffle(b,b+n);
int cur=0;
for(int j=0;j<m;j++){
if(b[j]<l)cur++;
}
ans[cur]++;
}
for(int i=n-1;i>=0;i--)ans[i]+=ans[i+1];
int rep=0;
for(int i=n;i>=0;i--){
if(ans[i]>=LIM/2){
rep=i;
break;
}
}
printf("%d\n",rep);*/
}
return 0;
}

G. Medals

将第$x$名的费用设置为$1001^{10-x}$,那么答案就是二分图最大权匹配,费用流求解即可,需要用__int128存储。

#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 __int128 LL;
typedef pair<int,int>pi;
const int Maxn=2020,Maxe=200020;
LL Inf=1LL<<60;
LL pw[15];
int ne;
int n,s,t;
vector<int>G[Maxn];
struct E{
int v,c;
LL w;
E(){}
E(int v,int c,LL w):v(v),c(c),w(w){}
}e[Maxe];
void add(int u,int v,int c,LL w){
e[ne]=E(v,c,w);
G[u].push_back(ne++);
e[ne]=E(u,0,-w);
G[v].push_back(ne++);
}
int pre[Maxn],pe[Maxn],inq[Maxn];
LL d[Maxn];
bool spfa(){
for(int i=0;i<=t;i++)d[i]=Inf,inq[i]=0;
d[s]=0;
queue<int>q;
q.push(s);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<G[u].size();i++){
int id=G[u][i];
int v=e[id].v;
LL w=e[id].w;
int c=e[id].c;
if(!c)continue;
if(d[v]>d[u]+w){
pre[v]=u;
pe[v]=id;
d[v]=d[u]+w;
if(!inq[v]){q.push(v);inq[v]=1;}
}
}
inq[u]=0;
}
return d[t]<0;
}
int rep[100];
int cho[Maxn];
void costflow(){
LL ans=0;
while(spfa()){
ans-=d[t];
for(int i=t;i!=s;i=pre[i]){
e[pe[i]].c--;
e[pe[i]^1].c++;
}
}
for(int i=0;i<10;i++)rep[10-i]=ans%1001,ans/=1001;
for(int i=1;i<=10;i++)printf("%d%c",rep[i],i==10?'\n':' ');
for(int i=1;i<=n;i++){
cho[i]=0;
for(int j=0;j<G[i].size();j++){
int id=G[i][j];
if(e[id].v!=s&&(!e[id].c)){
cho[i]=e[id].v-n;
}
}
}
for(int i=1;i<=n;i++)printf("%d%c",cho[i],i==n?'\n':' ');
}
int main(){
freopen("medals.in","r",stdin);
freopen("medals.out","w",stdout);
pw[0]=1;
Inf*=Inf;
for(int i=1;i<=11;i++)pw[i]=pw[i-1]*1001;
scanf("%d",&n);
for(int i=1;i<=n;i++){
int k;scanf("%d",&k);
for(int j=0;j<k;j++){
int id,rk;
scanf("%d%d",&id,&rk);
add(i,id+n,1,-pw[10-rk]);
}
add(s,i,1,0);
}
s=0;t=n+1000+1;
for(int i=n+1;i<t;i++)add(i,t,1,0);
costflow();
return 0;
}

  

H. Reachability

对于每个询问,压位记忆化搜索即可。

时间复杂度$O(\frac{qn^3}{64})$。

#include<cstdio>
#include<bitset>
using namespace std;
typedef unsigned int U;
const int N=405;
typedef bitset<N>DS;
int n,m,i,A,B;bool g[N][N],v[N];
U pa[N],pb[N];
DS f[N];
void dfs(int x){
if(v[x])return;
v[x]=1;
for(int i=1;i<=n;i++)if(g[x][i]){
dfs(i);
f[x]|=f[i];
}
}
inline void vio(){
int i,j;
for(i=1;i<=n;i++){
v[i]=0,f[i].reset();
f[i][i]=1;
}
for(i=1;i<=n;i++)if(!v[i])dfs(i);
U ret=0;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(f[i][j]==1&&i!=j){
// printf("%d->%d\n",i,j);
ret+=pa[i-1]*pb[j-1];
}
printf("%u\n",ret);
}
int main(){
freopen("reachability.in","r",stdin);
freopen("reachability.out","w",stdout);
scanf("%d%d%d%d",&n,&m,&A,&B);
for(pa[0]=i=1;i<=n;i++)pa[i]=pa[i-1]*A;
for(pb[0]=i=1;i<=n;i++)pb[i]=pb[i-1]*B;
for(i=1;i<=m;i++){
char op1[5],op2[5];
int x,k,y;
scanf("%s%s%d%d",op1,op2,&x,&k);
if(op2[0]=='o'){
while(k--)scanf("%d",&y),g[x][y]^=1;
}else{
while(k--)scanf("%d",&y),g[y][x]^=1;
}
vio();
}
return 0;
}

  

I. Revolving Lasers

留坑。

J. Snakes on the Stone

从蛇头开始走,每次碰到交点就往上走即可,这样一定可以保证不打结。

#include <bits/stdc++.h>
using namespace std ; typedef long long LL ;
typedef pair < int , int > pii ; #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 30 ; int a[MAXN][MAXN] , n , m[3] ;
int vis[MAXN][MAXN] ;
int x[3][MAXN * MAXN] , y[3][MAXN * MAXN] ; void solve () {
clr ( a , 0 ) ;
clr ( vis , 0 ) ;
for ( int i = 0 ; i < n ; ++ i ) {
scanf ( "%d" , &m[i] ) ;
for ( int j = 1 ; j <= m[i] ; ++ j ) {
scanf ( "%d%d" , &x[i][j] , &y[i][j] ) ;
vis[x[i][j]][y[i][j]] ++ ;
}
}
for ( int i = 0 ; i < n ; ++ i ) {
for ( int j = 1 ; j <= m[i] ; ++ j ) {
int r = x[i][j] , c = y[i][j] ;
if ( vis[r][c] == 2 ) {
if ( !a[r][c] ) {
++ a[r][c] ;
putchar ( '-' ) ;
} else {
putchar ( '+' ) ;
}
}
}
puts ( "" ) ;
}
} int main () {
freopen ( "snakes2.in" , "r" , stdin ) ;
freopen ( "snakes2.out" , "w" , stdout ) ;
while ( ~scanf ( "%d" , &n ) ) solve () ;
return 0 ;
}

  

K. Dependent Subsets

选出的这些向量的秩只能是$1$或$2$,枚举一个基向量,用它去对其它向量进行消元,约分之后排序,首先被消完的向量都可以选入,然后再选若干个约分后完全相等的向量即可。

时间复杂度$O(n^2d)$。

#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;
const int Maxn=1020;
int n,d;
vector<int> a[Maxn];
vector<int> b[Maxn];
int id[Maxn];
int use[Maxn];
int st[Maxn];
bool cmp(int t1,int t2){
return b[t1]<b[t2];
}
int xiao(vector<int>&x){//return first nonzero loc
int fst=x.size();
for(int i=0;i<x.size();i++){
if(x[i]!=0){fst=i;break;}
}
if(fst>=x.size())return fst;
int gc=abs(x[fst]);
for(int i=fst+1;i<x.size();i++){
if(x[i]!=0){
gc=__gcd(abs(x[i]),gc);
}
}
int tmp=x[fst]<0?(-gc):gc;
for(int i=fst;i<x.size();i++){
if(x[i]!=0)x[i]=x[i]/tmp;
}
return fst;
}
vector<int> dec(vector<int>&x,vector<int>&y,int st1,int st2){
if(!y[st1])return y;
vector<int>ret=x;
int lcm=x[st1]*abs(y[st1])/__gcd(x[st1],abs(y[st1]));
int be1=lcm/x[st1],be2=lcm/y[st1];
for(int i=0;i<x.size();i++)ret[i]=x[i]*be1-y[i]*be2;
return ret;
}
void pt(vector<int>&x){
for(int i=0;i<x.size();i++)printf("%d ",x[i]);puts("");
}
bool iszero(vector<int>&x){
for(int i=0;i<x.size();i++)if(x[i])return 0;
return 1;
}
int main(){
freopen("subset.in","r",stdin);
freopen("subset.out","w",stdout);
scanf("%d%d",&n,&d);
for(int i=1;i<=n;i++){
for(int j=0;j<d;j++){
int x;scanf("%d",&x);
a[i].push_back(x);
}
}
for(int i=1;i<=n;i++)st[i]=xiao(a[i]);
vector<int>rep;
for(int i=1;i<=n;i++){
int cnt=0;
for(int j=i+1;j<=n;j++){
b[cnt]=dec(a[i],a[j],st[i],st[j]);
xiao(b[cnt]);
use[cnt]=cnt;
id[cnt]=j;
cnt++;
}
sort(use,use+cnt,cmp);
int sel=-1,sr;
int now=0;
vector<int>tmp;
tmp.push_back(i);
for(;now<cnt&&iszero(b[use[now]]);now++)tmp.push_back(id[use[now]]);
int tmpans=0;
for(int j=now,k;j<cnt;j=k){
for(k=j+1;k<cnt&&b[use[k]]==b[use[j]];k++);
if((k-j)>tmpans){
sel=j;
sr=k;
tmpans=k-j;
}
}
if(sel>=0){
for(int j=sel;j<sr;j++)tmp.push_back(id[use[j]]);
}
if(tmp.size()>rep.size())swap(tmp,rep);
}
printf("%d\n",(int)rep.size());
for(int i=0;i<rep.size();i++)printf("%d%c",rep[i],i==rep.size()-1?'\n':' ');
return 0;
}

  

上一篇:Java虚拟机----垃圾回收与内存分配


下一篇:vs2010使用C