博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
2016-2017 ACM-ICPC, NEERC, Moscow Subregional Contest
阅读量:5884 次
发布时间:2019-06-19

本文共 9658 字,大约阅读时间需要 32 分钟。

A. Altitude

从小到大加入每个数,用set查找前驱和后继即可。

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

#include 
using namespace std ;const int Maxn=100020,Inf=1e9;typedef pair
pi;int n;int a[Maxn];vector
V;set
S;int ans,rep1,rep2,rep3;int caldis(int x,int y){ return y>x?(y-x):(y+n-x);}void ask(int loc){ if(!S.size())return ; set
::iterator it=S.lower_bound(loc); set
::iterator it2=it; for(int i=0;i<2;i++){ if(it2==S.begin()){it2=S.end();it2--;} else it2--; } int ret1=Inf,ret2=Inf,cs1,cs2; for(int i=0;i<5;i++){ int t1=caldis(*it2,loc); int t2=caldis(loc,*it2); if(t1

  

B. Blocking Buffer

观察发现$\gcd(r,w)$都是可以达到的,于是欧几里得求一下即可。

#include 
using namespace std ;const int Maxn=200020,Inf=1e9;typedef pair
pi;typedef long long LL;bool solve(LL l,LL A,LL B){ if(l-B>=A-1)return 0; LL gc=__gcd(A,B); LL tmp=(l-B)/gc*gc; while(tmp<=l-B)tmp+=gc; if(tmp
>l>>A>>B){ /* set
S; LL cur=0; bool flag=1; S.insert(0); while(1){ if(cur>l-B&&cur
=A){ cur%=A; } else{ cur=(l-cur)/B*B+cur; } if(S.find(cur)!=S.end()){break;} } puts(flag?"OK":"DEADLOCK"); */ puts(solve(l,A,B)?"DEADLOCK":"OK"); } return 0 ;}

  

C. Catch Me If You Can

留坑。

 

D. Demolition Time

留坑。

 

E. Economy Printing

将数字从小到大排序,那么第$i$个数要么自己作为开头,要么和$i-2$连接,要么和$i-1$连接,设$f[i][j][k]$表示考虑了前$i$个数,第$i-1$个数用操作$j$,第$i$个数用操作$k$时的最小串长,然后DP即可。

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

#include 
using namespace std ;typedef pair < int , int > pii ;#define clr( a , x ) memset ( a , x, sizeof a )const int MAXN = 200005 ;const int INF = 0x3f3f3f3f ;int n ;int len[MAXN] ;int a[MAXN] ;int dp[MAXN][4][4] ;int f[MAXN] ;pii p[MAXN][4][4] ;int vis[MAXN] ;int calc ( int x ) { int t = 0 ; while ( x ) { t ++ ; x /= 10 ; } return t ;}void dfs ( int n , int x , int y ) { if ( n == 1 ) return ; int nx = p[n][x][y].first ; int ny = x ; f[n] = p[n][x][y].second ; dfs ( n - 1 , nx , ny ) ;}int dfs2 ( int x ) { vis[x] = 1 ; if ( f[x] == 0 ) return x ; return dfs2 ( f[x] ) ;} void solve () { for ( int i = 1 ; i <= n ; ++ i ) { scanf ( "%d" , &a[i] ) ; } sort ( a + 1 , a + n + 1 ) ; for ( int i = 1 ; i <= n ; ++ i ) { len[i] = calc ( a[i] ) ; } clr ( f , 0 ) ; clr ( p , 0 ) ; clr ( dp , INF ) ; dp[0][0][0] = 0 ; for ( int i = 1 ; i <= n ; ++ i ) { for ( int j = 0 ; j < 4 ; ++ j ) { for ( int k = 0 ; k < 4 ; ++ k ) if ( dp[i - 1][j][k] != INF ) { for ( int l = 0 ; l < 4 ; ++ l ) { int tmp = dp[i - 1][j][k] + 1 + len[i] ; if ( l ) tmp = tmp + 1 + len[i] ; if ( l == 1 && a[i] % 2 == 0 ) continue ; if ( l == 2 && a[i] % 2 == 1 ) continue ; if ( dp[i][k][l] > tmp ) { dp[i][k][l] = tmp ; p[i][k][l] = pii ( j , 0 ) ; } } if ( j == 1 || j == 2 ) { if ( i > 2 && a[i] - a[i - 2] == 2 ) { int tmp = dp[i - 1][j][k] + len[i] - len[i - 2] ; if ( dp[i][k][j] > tmp ) { dp[i][k][j] = tmp ; p[i][k][j] = pii ( j , i - 2 ) ; } } } if ( k == 1 || k == 2 ) { if ( i > 1 && a[i] - a[i - 1] == 2 ) { int tmp = dp[i - 1][j][k] + len[i] - len[i - 1] ; if ( dp[i][k][k] > tmp ) { dp[i][k][k] = tmp ; p[i][k][k] = pii ( j , i - 1 ) ; } } } if ( k == 3 ) { if ( i > 1 && a[i] - a[i - 1] == 1 ) { int tmp = dp[i - 1][j][k] + len[i] - len[i - 1] ; if ( dp[i][k][k] > tmp ) { dp[i][k][k] = tmp ; p[i][k][k] = pii ( j , i - 1 ) ; } } } } } } int ans = INF , x = -1 , y = -1 ; for ( int i = 0 ; i < 4 ; ++ i ) { for ( int j = 0 ; j < 4 ; ++ j ) { if ( dp[n][i][j] < ans ) { ans = dp[n][i][j] ; x = i ; y = j ; } } } dfs ( n , x , y ) ; //printf ( "%d\n" , ans - 1 ) ; clr ( vis , 0 ) ; int flag = 0 ; for ( int i = n ; i >= 1 ; -- i ) if ( !vis[i] ) { int L = dfs2 ( i ) ; if ( flag ) putchar ( ',' ) ; flag = 1 ; if ( L == i ) printf ( "%d" , a[i] ) ; else { printf ( "%d" , a[L] ) ; if ( a[i] - a[f[i]] == 2 ) { if ( a[i] % 2 == 0 ) putchar ( '%' ) ; else putchar ( '#' ) ; } else putchar ( '-' ) ; printf ( "%d" , a[i] ) ; } } puts ( "" ) ;}int main () { while ( ~scanf ( "%d" , &n ) ) solve () ; return 0 ;}

  

F. Format

枚举有没有"^"符号,然后将字符分成三类:可选可不选、必须要选、必须不能选。

设$f[i]$表示处理完字典序最小的$i$个字符时的最短串长以及对应串长的字典序最小串,然后枚举往前延伸到哪里转移。

需要注意的是,如果全部字符都出现了,那么答案应该是%[^!],需要特判。

#include
#include
#include
#include
#include
using namespace std;typedef pair
P;const int N=300;int n,i,j,v[N];char s[222222];P ans(N,""),f[N];inline bool check(char x){ if(x==' ')return 1; if(x>='0'&&x<='9')return 1; if(x>='a'&&x<='z')return 1; if(x>='A'&&x<='Z')return 1; return 0;}void dp(){ for(i=32;i<=126;i++){ f[i]=P(N,""); if(v[i]==0||v[i]==2){ P t=f[i-1]; f[i]=t; } if(v[i]==0||v[i]==1){ for(j=i;j>=32;j--){ if(v[j]==2)break; P t=f[j-1]; if(j==i){ t.first++; t.second.push_back(char(i)); }else if(j+1==i){ t.first+=2; t.second.push_back(char(j)); t.second.push_back(char(i)); }else{ t.first+=3; t.second.push_back(char(j)); t.second+="-"; t.second.push_back(char(i)); } f[i]=min(f[i],t); } } }}int main(){ fgets(s,111111,stdin); n=strlen(s); //0 : can choose and can not choose //1 : must choose //2 : mustn't choose for(i=32;i<=126;i++)v[i]=0; for(i=0;i
1)ans=min(ans,f[126]);else ans=min(ans,P(2,"%[^!")); ans.second+="]"; cout<
<

  

G. Great Guest Gathering

分成$n$轮构造即可。

#include 
using namespace std ;int n ;void solve () { printf ( "%d %d %d\n" , 1 , 1 , 0 ) ; for ( int i = 1 ; i < n ; ++ i ) { for ( int j = i + 2 ; j <= n ; ++ j ) { printf ( "%d %d %d\n" , j , j , i ) ; printf ( "%d %d %d\n" , i , i , j ) ; } printf ( "%d %d %d\n" , i + 1 , i + 1 , i ) ; } for ( int i = n - 1 ; i >= 2 ; -- i ) { printf ( "%d %d %d\n" , i , i , i + 1 ) ; } printf ( "%d %d %d\n" , 0 , 1 , 2 ) ;}int main () { while ( ~scanf ( "%d" , &n ) ) solve () ; return 0 ;}

  

H. Hockey Cup

按题意模拟即可。

#include 
using namespace std ;const int Maxn=200020,Inf=1e9;typedef pair
pi;typedef long long LL;map
Mp;string ts[]={"Russia","Sweden","Finland","NA"};int res[4][4][3];int sc[4][6];int g[4][4];int cmpop;bool cmp(int a,int b){ return sc[a][cmpop]>sc[b][cmpop];}void solve(vector
&v,int ty){ if(v.size()<=2){ if(v.size()==1)return ; if(v.size()==2){ if(!g[v[0]][v[1]])swap(v[0],v[1]); } return ; } cmpop=ty; sort(v.begin(),v.end(),cmp); vector
rv; for(int i=0,j;i
tmp; for(j=i;j
v; for(int i=0;i<4;i++)v.push_back(i); solve(v,0); if(!v[0]||!v[1])return 1<<1; return 1<<0;}int check(){ memset(sc,0,sizeof sc); int ret=0; for(int i=0;i<4;i++){ for(int j=i+1;j<4;j++){ int t1=res[i][j][0],t2=res[i][j][1]; int t3=res[i][j][2]; int ti=i,tj=j; g[i][j]=1;g[j][i]=0; if(t1
>name1>>name2>>t1>>t2; fgets(ss,sizeof ss,stdin); if(strlen(ss)>=2){ t3=1; } else t3=0; int id1=Mp[name1],id2=Mp[name2]; if(id1>id2){swap(t1,t2);swap(id1,id2);} res[id1][id2][0]=t1; res[id1][id2][1]=t2; res[id1][id2][2]=t3; } cin>>name1>>name2; int id1=Mp[name1],id2=Mp[name2]; int ans=0; if(id1>id2)swap(id1,id2); for(int i=0;i<100;i++){ for(int j=0;j<100;j++){ if(i==j)continue; res[id1][id2][0]=i; res[id1][id2][1]=j; res[id1][id2][2]=0; ans|=check(); if(abs(i-j)==1){ res[id1][id2][2]=1; ans|=check(); } } } if(ans==3)puts("Believe in playoff!"); else if(ans==2)puts("Already in playoff!"); else puts("No chance"); return 0 ;}

  

I. Interesting Interactive Idea

留坑。

 

J. Juice Degustation

留坑。

 

K. Knights of the Old Republic

考虑对图做集合DP,设$f[S]$表示占领S集合的最小代价,考虑从小到大加入每条边,加入每条边时,如果形成环,那么显然可以扔掉。

否则$f[S]=\min(f[A]+f[B],\min(A中费用最小的点,B中费用最小的点)\times\max(A中需求最大的点,B中需求最大的点,当前边权))$。

在Kruskal的时候用并查集维护即可。

时间复杂度$O(m\log m)$。

#include 
using namespace std ;typedef long long LL ;const int MAXN = 300005 ;struct Edge { int u , v , c ; bool operator < ( const Edge& a ) const { return c < a.c ; }} ;Edge E[MAXN] ;int a[MAXN] , b[MAXN] , p[MAXN] ;LL sum[MAXN] ;int n , m ;int F ( int x ) { return p[x] == x ? x : ( p[x] = F ( p[x] ) ) ;}void solve () { for ( int i = 1 ; i <= n ; ++ i ) { p[i] = i ; } for ( int i = 1 ; i <= n ; ++ i ) { scanf ( "%d%d" , &a[i] , &b[i] ) ; sum[i] = 1LL * a[i] * b[i] ; } for ( int i = 0 ; i < m ; ++ i ) { scanf ( "%d%d%d" , &E[i].u , &E[i].v , &E[i].c ) ; } sort ( E , E + m ) ; for ( int i = 0 ; i < m ; ++ i ) { int x = F ( E[i].u ) ; int y = F ( E[i].v ) ; if ( x == y ) continue ; int na = max ( max ( a[x] , a[y] ) , E[i].c ) ; int nb = min ( b[x] , b[y] ) ; LL tmp = 1LL * na * nb ; sum[y] = min ( sum[x] + sum[y] , tmp ) ; p[x] = y ; a[y] = na ; b[y] = nb ; } LL ans = 0 ; for ( int i = 1 ; i <= n ; ++ i ) { if ( F ( i ) == i ) ans += sum[i] ; } printf ( "%lld\n" , ans ) ;}int main () { while ( ~scanf ( "%d%d" , &n , &m ) ) solve () ; return 0 ;}

  

L. Lazy Coordinator

从后往前处理,维护当前时刻到每个时刻被选用的概率乘以时刻之和,减去当前出题人报名的时间即可。

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

#include 
using namespace std ;const int Maxn=200020,Inf=1e9;typedef pair
pi;int n;int arr[Maxn];char op[Maxn];int tl[Maxn],has[Maxn],idx[Maxn];double ans[Maxn];int main () { scanf("%d",&n); int cnt=0,id=0; for(int i=1;i<=n*2;i++){ scanf(" %c%d",&op[i],&tl[i]); idx[i]=-1; if(op[i]=='+'){ id++; arr[id]=tl[i]; idx[i]=id; cnt++; } else{ cnt--; } has[i]=cnt; } double sum=0; for(int i=n*2;i>=1;i--){ if(op[i]=='-'){ int k=has[i]+1; sum=sum*(1.0-1.0/k)+tl[i]*(1.0/k); } else ans[idx[i]]=sum; } for(int i=1;i<=n;i++)printf("%.12f\n",ans[i]-arr[i]); return 0 ;}

  


总结:

  • E题思考方向错了,在错误的道路上越走越远,以致最后半小时想出正解却没有时间写完。
  • G题poursoul没过样例就自信提交,导致在样例WA,下次要注意。

 

转载地址:http://owlix.baihongyu.com/

你可能感兴趣的文章
今年全球游戏市场13%的收入将属于腾讯
查看>>
Git 远程推送被拒绝的一种解决方案
查看>>
《战争论》核心原则
查看>>
阿里云云数据库RDS秒级监控功能解锁,通宵加班找故障将成为过去式
查看>>
Ubuntu常用软件安装(附截图软件、FTP、卸载命令)
查看>>
以太坊MetaMask钱包插件使用教程
查看>>
技术大牛论道HBase 3.0 可能的新特性
查看>>
WPF Binding学习(四) 绑定各种数据源
查看>>
使用Swashbuckle构建RESTful风格文档
查看>>
Keras框架简介
查看>>
CentOS7安装Nginx、MySQL、PHP
查看>>
2018前端面试总结js部分【中】
查看>>
k邻近算法
查看>>
echarts中如何使用timeline组件
查看>>
实现jul 日志重定向到 slf4j
查看>>
Linux清除Windows密码
查看>>
浅谈几个前端异步解决方案
查看>>
Hbase集群搭建及所有配置调优参数整理及API代码运行
查看>>
世界首个AR交友应用上线,再也不用担心找不到对象啦!
查看>>
CakePHP 4.0.0 alpha1 发布,PHP 快速开发框架
查看>>