A Artwork :并查集倒着推
//题目原型,删点之后图上还剩下多少个联通块
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int MAXM=11000;
const int MAXN=1100;
bool del[MAXN][MAXN];
int fa[MAXN*MAXN];
int find(int x)
{
return fa[x]==-1?x:fa[x]=find(fa[x]);
}
bool unite(int a,int b)
{
int t1=find(a),t2=find(b);
if(t1==t2) return false;
fa[t1]=t2;
return true;
}
struct point_t
{
int x,y;
point_t() {}
point_t(int _x,int _y):x(_x),y(_y) {}
};
struct line_t
{
point_t a,b;
line_t() {}
line_t(point_t _a,point_t _b):a(_a),b(_b) {}
}question[MAXM];
vector<int> vec[MAXM];
const int L[]={1,0,-1,0};
const int R[]={0,1,0,-1};
int get_hashs(int x,int y,int n)
{
x--,y--;
return x*n+y;
}
int answer[MAXM];
int change(int x,int y,int n,int m)
{
int ret=1;
for(int i=0;i<4;i++)
{
int tempx=x+L[i],tempy=y+R[i];
if(tempx<1||tempx>n||tempy<1||tempy>m||del[tempx][tempy]) continue;
if(unite(get_hashs(x,y,m),get_hashs(tempx,tempy,m))) ret--;
}
return ret;
}
int main()
{
// freopen("in.txt","r",stdin);
int n,m,q;
while(scanf("%d%d%d",&n,&m,&q)!=EOF)
{
for(int i=1;i<=1;i++)
vec[i].clear();
memset(fa,-1,sizeof(fa));
memset(del,false,sizeof(del));
for(int i=1;i<=q;i++)
{
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
question[i]=line_t(point_t(x1,y1),point_t(x2,y2));
}
//然后离线开始慢慢加边
for(int i=1;i<=q;i++)
{
if(question[i].a.x==question[i].b.x)
{
int x=question[i].a.x;
for(int j=question[i].a.y;j<=question[i].b.y;j++)
{
if(del[x][j]) continue;
del[x][j]=true;
vec[i].push_back(j);
}
}
else
{
int y=question[i].a.y;
for(int j=question[i].a.x;j<=question[i].b.x;j++)
{
if(del[j][y]) continue;
del[j][y]=true;
vec[i].push_back(j);
}
}
}
// for(int i=1;i<=q;i++)
// {
// printf("question :%d\n",i);
// for(int j=0;j<vec[i].size();j++)
// printf("%d ",vec[i][j]);
// printf("\n")
// }
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(del[i][j]) continue;
// printf("No DEl :%d %d\n",i,j);
for(int k=0;k<4;k++)
{
int x=i+L[k],y=j+R[k];
if(x<1||x>n||y<1||y>m) continue;
if(del[x][y]) continue;
int new1=get_hashs(i,j,m);
int new2=get_hashs(x,y,m);
unite(new1,new2);
// printf("new1 :%d new2 :%d\n",new1,new2);
}
}
int total=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(del[i][j]) continue;
int hashed=get_hashs(i,j,m);
if(fa[hashed]==-1) total++;
// printf("hashed :(%d,%d) %d \n",i,j,fa[hashed]);
}
answer[q]=total;
for(int i=q;i>=2;i--)
{
//然后加上删去的方块,看有多少个
line_t line=question[i];
// printf("(%d,%d)->(%d,%d)\n",line.a.x,line.a.y,line.b.x,line.b.y);
int blocks=answer[i];
if(line.a.x==line.b.x)
{
int x=line.a.x;
for(int j=0;j<vec[i].size();j++)
{
//如果这个方块已经被删去了,那么加上他
int mmp=vec[i][j];
if(del[x][mmp])
{
del[x][mmp]=false;
blocks+=change(x,mmp,n,m);
}
}
answer[i-1]=blocks;
}
else
{
int y=line.a.y;
for(int j=0;j<vec[i].size();j++)
{
int mmp=vec[i][j];
if(del[mmp][y])
{
del[mmp][y]=false;
int temp=change(mmp,y,n,m);
blocks+=temp;
}
}
answer[i-1]=blocks;
}
}
for(int i=1;i<=q;i++)
printf("%d\n",answer[i]);
}
return 0;
}
B Bless You Autocorrect! : 字典树+bfs(其实没必要用spfa求得最短路,因为每条边的距离都是1,所以bfs可以直接求得距离,qaq)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int SIZE=1111111;
struct node_t
{
int son[28];
int idx;
}node[SIZE];
//其中26记录的是fa节点,27记录的是tab节点
int toUsed;
char word[SIZE];
void init()
{
toUsed=1;
memset(node,-1,sizeof(node_t));
}
inline int _newnode()
{
memset(node+toUsed,-1,sizeof(node_t));
return toUsed++;
}
void insert(const char *str,int idx)
{
int root=0;
for(int i=0;str[i];i++)
{
int sn=str[i]-'a';
if(node[root].son[sn]==-1) node[root].son[sn]=_newnode();
node[node[root].son[sn]].son[26]=root;
root=node[root].son[sn];
}
int cur=0;
for(int i=0;str[i];i++)
{
int sn=str[i]-'a';
cur=node[cur].son[sn];
if(node[cur].son[27]==-1) node[cur].son[27]=toUsed-1;
}
node[root].idx=idx;
// printf("Word :%s table[%d] :%d\n",word,idx,table[idx]);
}
//搜索每一个节点tab键后会跳转到哪里
//对于每个要查询的字符串,我们首先找到其能在字典树上匹配到的最大长度,其次然后做bfs求得最短距离
//记录0点到每一个点之间的最短距离
int dist[SIZE];
bool vis[SIZE];
void spfa(int s)
{
memset(vis,false,sizeof(vis));
memset(dist,0x3f,sizeof(dist));
vis[s]=true;dist[s]=0;
node[s].son[27]=-1;
queue<int> que;
while(!que.empty()) que.pop();
que.push(s);
while(!que.empty())
{
int u=que.front();
que.pop();
vis[u]=true;
for(int i=0;i<28;i++)
{
if(node[u].son[i]==-1) continue;
int v=node[u].son[i];
if(dist[v]>dist[u]+1)
{
dist[v]=dist[u]+1;
// if(v==7) printf("from %d -> %d :%d\n",u,v,dist[v]);
if(!vis[v])
{
vis[v]=true;
que.push(v);
}
}
}
}
}
int query(const char *str)
{
//i记录能匹配到的最大长度
int i,final_node=0;
for(i=0;str[i];i++)
{
int sn=str[i]-'a';
if(node[final_node].son[sn]==-1) break;
final_node=node[final_node].son[sn];
}
//然后bfs求得从0点到final点的最短距离
int lens=strlen(str);
// printf("final_node :%d %d + %d\n",final_node,dist[final_node],lens-i);
return dist[final_node]+lens-i;
}
int main()
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
for(int i=0;i<n;i++)
{
scanf("%s",word);
insert(word,i);
}
spfa(0);
for(int i=0;i<m;i++)
{
scanf("%s",word);
int ans=query(word);
printf("%d\n",ans);
}
printf("\n");
}
return 0;
}
C Card Hand Sorting :暴力枚举 + 最长公共子序列
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
//枚举((2^4)*4!)种排列组合,求得最少要移动多少次
const int MAXN=60;
struct pock_t
{
int ranks;
char suits;
pock_t() {}
pock_t(int _ranks,char _suits):ranks(_ranks),suits(_suits) {}
}pock[MAXN],temp[MAXN];
int trans(char x)
{
if(x>='2'&&x<='9') return x-'0';
else if(x=='T') return 10;
else if(x=='J') return 11;
else if(x=='Q') return 12;
else if(x=='K') return 13;
else return 14;
}
//然后爆搜加上枚举生成每种排列组合
const char suits[]={'s','h','d','c'};
char change[4];
int up_down[4];
bool vis[4];
int n,ans;
int find(char suit)
{
for(int i=0;i<4;i++)
if(change[i]==suit) return i;
return -1;
}
bool cmp(const pock_t& a,const pock_t& b)
{
//首先如果花色相同
int fucka=find(a.suits),fuckb=find(b.suits);
if(a.suits==b.suits)
{
if(up_down[fucka]==1) return a.ranks<b.ranks;
else return a.ranks>b.ranks;
}
else return fucka<fuckb;
}
//记录最长上升子序列
int dp[MAXN][MAXN];
void solve()
{
memcpy(temp,pock,sizeof(pock));
sort(temp+1,temp+n+1,cmp);
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(pock[i].ranks==temp[j].ranks&&pock[i].suits==temp[j].suits)
dp[i][j]=dp[i-1][j-1]+1;
else dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
ans=min(ans,n-dp[n][n]);
}
void dfs(int depth)
{
if(depth==4) solve();
else
{
for(int i=0;i<4;i++)
{
if(vis[i]) continue;
vis[i]=true;
up_down[depth]=1;
change[depth]=suits[i];
dfs(depth+1);
up_down[depth]=-1;
change[depth]=suits[i];
dfs(depth+1);
vis[i]=false;
}
}
}
int main()
{
// freopen("in.txt","r",stdin);
while(scanf("%d",&n)!=EOF)
{
char tra,suit;
for(int i=1;i<=n;i++)
{
cin>>tra>>suit;
pock[i]=pock_t(trans(tra),suit);
}
ans=0x3f3f3f3f;
memset(vis,false,sizeof(vis));
dfs(0);
cout<<ans<<endl;
}
return 0;
}
D Daydreaming Stockbroker (dp)
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int MAXN=400;
LL dp[MAXN];
LL stock[MAXN];
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
cin>>stock[i];
dp[1]=100;
//其实也可以选择一直不买,反正结果的时候比一比就知道了
for(int i=2;i<=n;i++)
{
// puts("MMP");
LL no_buy=0;
for(int j=1;j<i;j++)
{
//其实也可以选择当天不买
no_buy=max(no_buy,dp[j]);
LL win=(stock[i]-stock[j]);
if(win<0) continue;
LL could_buy=dp[j]/stock[j];
LL rem=dp[j]%stock[j];
if(could_buy>100000)
{
rem+=(could_buy-100000)*stock[j];
could_buy=100000;
}
dp[i]=max(dp[i],rem+stock[i]*(could_buy));
// cout<<dp[i]<<endl;
}
dp[i]=max(no_buy,dp[i]);
// printf("dp[%d] :%d\n",i,dp[i]);
}
cout<<dp[n]<<endl;
}
return 0;
}