A - Triangles
记忆化搜索嘛。搜索以某三角形为顶的最大面积,注意边界情况。
#include <stdio.h>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
#define lson o<<1
#define rson o<<1|1
#define max(a,b) (a)>(b)?(a):(b)
#define min(a,b) (a)<(b)?(a):(b)
#define INF 200000000
typedef long long ll;
int dp[110][220];
char g[110][220];
int main(){
int n,h,cs=1;
while(scanf("%d",&n) && n){
for(int i=0;i<n;i++)scanf("%s",g[i]);
memset(dp,0,sizeof dp);
printf("Triangle #%d\n",cs++);
if(n==1){
printf("The largest triangle area is %d.\n\n",g[0][0]=='#'?0:1);
continue;
}
h=0;
for(int j=0;j<2*n-1;j++)if(g[0][j]!='#')dp[0][j]=h=1;
for(int i=1;i<n;i++){
int j;
for(j=0;j<2*(n-i);j+=2)if(g[i][j]!='#'){
int f=i-1,p=j+1;
while(f>=0&&g[f][p]!='#'&&g[f][p+1]!='#')f--,p+=2;
dp[i][j]=min(1+dp[i-1][j],i-f);
h=max(h,dp[i][j]);
}
}
if(g[n-2][1]!='#'){dp[n-2][1]=1;h=max(h,1);}
for(int i=n-3;i>=0;i--){
int j;
for(j=1;j<2*(n-i)-1;j+=2)if(g[i][j]!='#'){
if(j<2)dp[i][j]=1;
else{
int f=i+1,p=j-1;
while(f<n && j<2*(n-f)-1 && g[f][p]!='#' && g[f][p+1]!='#')f++;
dp[i][j]=min(1+dp[i+1][j-2],f-i);
}
h=max(h,dp[i][j]);
}
}
printf("The largest triangle area is %d.\n\n",h*h);
}
return 0;
}
B - Domino Effect
基本就是最短路问题,权值为正,最后要用 t=(dis[i]+dis[j]+g[i][j])/2.0 计算边上最后一个多米诺倒下的时间。
#include <stdio.h>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
#define lson o<<1
#define rson o<<1|1
#define max(a,b) (a)>(b)?(a):(b)
#define min(a,b) (a)<(b)?(a):(b)
#define INF 20000000000LL
typedef long long ll;
int g[505][505],n,m,vis[505];
ll d[505];
double t;int x,y;
void dijkstra(){
for(int i=2;i<=n;i++)d[i]=INF;
d[1]=0;
for(int i=0;i<n;i++){
int u;
ll tm=INF;
for(int j=1;j<=n;j++)if(!vis[j]&&d[j]<tm){
u=j;tm=d[j];
}
if(tm>=INF)break;
vis[u]=1;
for(int j=1;j<=n;j++)if(g[u][j]!=-1&&!vis[j])
d[j]=min(d[j],g[u][j]+d[u]);
}
for(int i=1;i<=n;i++){
if(t<d[i]){x=i;y=0;t=d[i];}
for(int j=1;j<i;j++)if(g[i][j]!=-1){
double temp=(g[i][j]+d[i]+d[j])/2.0;
if(t<temp){x=j;y=i;t=temp;}
}
}
}
int main(){
int a,b,l,cs=1;
while(scanf("%d%d",&n,&m) && n){
memset(g,-1,sizeof g);
memset(vis,0,sizeof vis);
t=0;x=1;y=0;
for(int i=0;i<m;i++){
scanf("%d%d%d",&a,&b,&l);
g[a][b]=g[b][a]=l;
}
dijkstra();
printf("System #%d\n",cs++);
if(!y){
printf("The last domino falls after %.1lf seconds, at key domino %d.\n\n",t,x);
}else{
printf("The last domino falls after %.1lf seconds, between key dominoes %d and %d.\n\n",t,x,y);
}
}
return 0;
}
这种题应该一看数据就知道是bfs可以水过的。
#include <stdio.h>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define STA 30000
int q[STA],d[STA],fa[STA],vis[STA],ans[STA];
int to[15][15],sw[15][15];
int n,k,s;
int bfs(int st){
int l,r;
l=r=0;
int now=(1<<st)*10+st-1;
q[r++]=now;
fa[now]=-1;
while(l<r){
now=q[l++];
int room=now%10+1,sta=now/10;
if(room==n&&sta==(1<<n))return 1;
int next;
for(int i=1;i<=n;i++)if(!vis[now-room+i] && to[room][i] && sta&(1<<i)){
next=now-room+i;
vis[next]=1;
d[next]=d[now]+1;
fa[next]=now;
q[r++]=next;
}
for(int i=1;i<=n;i++)if(i!=room && sw[room][i]){
if(!(sta&(1<<i)) && !vis[(sta|(1<<i))*10+room-1]){
next=(sta|(1<<i))*10+room-1;
vis[next]=1;
d[next]=d[now]+1;
fa[next]=now;
q[r++]=next;
}
else if(sta&(1<<i) && !vis[(sta^(1<<i))*10+room-1]){
next=(sta^(1<<i))*10+room-1;
vis[next]=1;
d[next]=d[now]+1;
fa[next]=now;
q[r++]=next;
}
}
}
return 0;
}
int main(){
//freopen("input.in","r",stdin);freopen("output.out","w",stdout);
int cs=1;
while(scanf("%d%d%d",&n,&k,&s) &&n){
int x,y;
memset(to,0,sizeof to);
memset(sw,0,sizeof sw);
memset(vis,0,sizeof vis);
memset(d,0,sizeof d);
while(k--){
scanf("%d%d",&x,&y);
to[x][y]=to[y][x]=1;
}
while(s--){
scanf("%d%d",&x,&y);
sw[x][y]=1;
}
printf("Villa #%d\n",cs++);
if(bfs(1)){
int u=(1<<n)*10+n-1,dis;
printf("The problem can be solved in %d steps:\n",dis=d[u]);
for(int i=0;i<dis;i++){
ans[i]=u;
u=fa[u];
}
int lastroom=1,sta0=1<<1,room,sta;
for(int i=dis-1;i>=0;i--){
room=ans[i]%10+1;sta=ans[i]/10;
if(room!=lastroom)printf("- Move to room %d.\n",room);
else{
for(int j=1;j<=n;j++)if((sta0&(1<<j))!=(sta&(1<<j))){
if(sta0&(1<<j))printf("- Switch off light in room %d.\n",j);
else printf("- Switch on light in room %d.\n",j);
break;
}
}
lastroom=room;sta0=sta;
}
printf("\n");
}else printf("The problem cannot be solved.\n\n");
}
return 0;
}
F - Decoding Morse Sequences
我的做法是把所有单词的Morse码编进Trie树,在词尾标记访问次数,然后记忆化搜索。
#include <stdio.h>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
#define lson o<<1
#define rson o<<1|1
#define max(a,b) (a)>(b)?(a):(b)
#define min(a,b) (a)<(b)?(a):(b)
#define INF 200000000
typedef long long ll;
int ch[1000010][3],sz;
char morse[26][10]
={".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..",
"--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."};
char s[10100],word[25],mod[100];
ll dp[10100];
int t[1000010];
void insert(char *s){
char *p=s;
int u=0;
for(;*p!='\0';p++){
int temp;
if(*p=='.')temp=1;
else temp=2;
if(ch[u][temp]==-1)ch[u][temp]=++sz;
u=ch[u][temp];
}
if(ch[u][0]==-1)ch[u][0]=++sz;
u=ch[u][0];
t[u]++;
}
ll dfs(int now){
if(dp[now]>=0)return dp[now];
ll &ans=dp[now];
ans=0;
int u=0,flag=1;
for(int i=now;s[i];i++){
int temp;
if(s[i]=='.')temp=1;
else temp=2;
if(ch[u][temp]==-1)return ans;
u=ch[u][temp];
if(ch[u][0]!=-1)ans+=t[ch[u][0]]*dfs(i+1);
}
return ans;
}
int main(){
//freopen("r.in","r",stdin);freopen("r.out","w",stdout);
int T;
scanf("%d",&T);
while(T--){
scanf("%s",s);
int m;
scanf("%d",&m);
memset(ch,-1,sizeof ch);
memset(t,0,sizeof t);
sz=0;
for(int i=0;i<m;i++){
mod[0]='\0';
scanf("%s",word);
for(int j=0;word[j];j++)
strcat(mod,morse[word[j]-'A']);
insert(mod);
}
memset(dp,-1,sizeof dp);
dp[strlen(s)]=1;
dfs(0);
printf("%lld\n",dp[0]);
}
return 0;
}
G - Fill the Cisterns!
二分答案,精度0.0005.
#include <stdio.h>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
#define lson o<<1
#define rson o<<1|1
#define max(a,b) (a)>(b)?(a):(b)
#define min(a,b) (a)<(b)?(a):(b)
#define INF 2000000
#define eps 5e-4
typedef long long ll;
struct cistern{
double b,h,s;
}c[50010];
double v,hmax,hmin;
int n;
int cmp(cistern a,cistern b){return a.b<b.b;}
int cal(double dh){
double vx=0;
for(int i=0;i<n&&c[i].b<dh;i++){
double t=min(c[i].b+c[i].h,dh);
vx+=(t-c[i].b)*c[i].s;
}
if(vx<v)return -1;
if(vx>v)return 1;
return 0;
}
double search(double low,double hi){
double mid;
while(hi-low>eps){
mid=(hi+low)/2.0;
if(cal(mid)>=0)hi=mid;
else low=mid;
}
return hi;
}
int main(){
//freopen("r.in","r",stdin);freopen("r.out","w",stdout);
int t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
double w,h,vmax;
hmax=0;hmin=INF;
vmax=0;
for(int i=0;i<n;i++){
scanf("%lf%lf%lf%lf",&c[i].b,&c[i].h,&w,&h);
c[i].s=w*h;
hmax=max(hmax,c[i].h+c[i].b);
hmin=min(hmin,c[i].b);
vmax+=c[i].s*c[i].h;
}
scanf("%lf",&v);
if(vmax<v){
printf("OVERFLOW\n");
continue;
}
sort(c,c+n,cmp);
double dh=search(hmin,hmax);
printf("%.2lf\n",dh);
}
return 0;
}
H - Horizontally Visible Segments
其实应该很快反应过来是线段树的……跟染色差不多的,每次询问一次更新一次,中间hash判重然后加边,最后暴力搜索得到 Triangle 个数。
有个细节是x,y在[0,8000],0<=n<=8000,建立的图应该是稀疏图,用vector存,所以一定要判重的!
#include <stdio.h>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#define rson o<<1|1
#define lson o<<1
#define H 16000
#define MOD 1403641
using namespace std;
vector <int> g[8010];
int col[16000<<2],y1,y2;
struct segment{
int y1,y2,x;
}seg[8010];
struct Hash{
int va;
Hash *next;
Hash(){va=-1;next=NULL;}
}hash[MOD];
void init(){
for(int i=0;i<MOD;i++){hash[i].va=-1;hash[i].next=NULL;}
}
int exist(int u,int v){
int x=u*10000+v;
if(hash[x%MOD].va==-1){hash[x%MOD].va=x;return 0;}
else{
Hash *u=&hash[x%MOD];
while(u->next!=NULL){
if(u->va==x)return 1;
u=u->next;
}
if(u->va==x)return 1;
u->next=new Hash;
u->next->va=x;u->next->next=NULL;
return 0;
}
}
int cmp(struct segment a,struct segment b){return a.x<b.x;}
void pushdown(int o,int l,int r){
if(col[o]!=-1){
col[rson]=col[lson]=col[o];
}
}
void upd(int o,int l,int r,int u){
if(y1<=l&&y2>=r){
col[o]=u;
}else if(y2>=l&&y1<=r){
int mid=(l+r)>>1;
pushdown(o,l,r);
col[o]=-1;
if(y1<=mid)upd(lson,l,mid,u);
if(y2>mid)upd(rson,mid+1,r,u);
}
}
void que(int o,int l,int r,int v){
int mid=(l+r)/2;
if(y1<=l&&y2>=r){
if(col[o]==-1){
que(lson,l,mid,v);
que(rson,mid+1,r,v);
}else if(col[o]&&!exist(v,col[o])){
g[v].push_back(col[o]);
}
}else if(y2>=l&&y1<=r){
pushdown(o,l,r);
if(y1<=mid)que(lson,l,mid,v);
if(y2>mid)que(rson,mid+1,r,v);
}
}
int main(){
int T,n;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d%d%d",&seg[i].y1,&seg[i].y2,&seg[i].x);
sort(seg+1,seg+n+1,cmp);
for(int i=1;i<=n;i++)g[i].clear();
memset(col,0,sizeof col);
init();
for(int i=1;i<=n;i++){
y1=seg[i].y1*2;y2=seg[i].y2*2;
if(i>1)que(1,0,H,i);
upd(1,0,H,i);
}
int cnt=0;
for(int i=3;i<=n;i++)if(g[i].size()>1)
for(int j=0;j<g[i].size();j++){
int u=g[i][j];
for(int k=0;k<g[u].size();k++)
for(int q=0;q<g[i].size();q++)if(g[i][q]==g[u][k])cnt++;
}
printf("%d\n",cnt);
}
return 0;
}
J - (Your)((Term)((Project)))
细节题了,递归做最保险,把里面没有运算符的删掉之后,再每次找匹配的括号,判断删除否,两个括号中间的部分再递归。
#include <stdio.h>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
#define lson o<<1
#define rson o<<1|1
#define max(a,b) (a)>(b)?(a):(b)
#define min(a,b) (a)<(b)?(a):(b)
#define INF 200000000
#define SKIP(p) while(*p==' ')++p;
typedef long long ll;
char s[300],q[300];
int res;
void solve(char *s,char *q){
char *p;
int sgn=1;
for(p=s;p<=q;p++){
if(*p=='+')sgn=1;
else if(*p=='-')sgn=-1;
else if(*p=='('){
char *t;
int cnt=1;
for(t=p+1;t<=q;t++){
if(*t=='(')cnt++;
else if(*t==')')cnt--;
if(!cnt)break;
}
if(sgn>0)*p=*t=' ';
if(t-p>2)solve(p+1,t-1);
}
}
}
void deal(char *p,int n){
for(int i=0;i<n;i++)if(p[i]<='Z'&&p[i]>='A'){
int l=i-1,r=i+1;
while(l>=0&&r<n){
if(p[l]!='('||p[r]!=')')break;
p[l]=p[r]=' ';
l--;r++;
}
}
solve(p,p+n-1);
}
int main(){
//freopen("r.in","r",stdin);freopen("r.out","w",stdout);
int t;
scanf("%d",&t);
gets(s);
while(t--){
gets(s);
char *p=s;
res=0;
for(;*p!='\0';p++){
SKIP(p);
q[res++]=*p;
}
deal(q,res);
for(int i=0;i<res;i++)if(q[i]!=' ')
printf("%c",q[i]);
printf("\n");
}
return 0;
}