首页 > 代码库 > Topcoder SRM 628 DIV 2
Topcoder SRM 628 DIV 2
被自己蠢哭了。。。。
250-point problem
国际象棋棋盘上给出两个坐标,问象从一个走到另一个最少要几步。
黑格象只能走黑格,白格象只能走白格,只要判断两个坐标的颜色是否相同就能判断是否可达,观察棋盘可以发现坐标的奇偶性决定了格子的颜色;可达的情况下最多两步就能达到,所以只要判断格子是否在同一条斜线上就行了。
#include<cstdio> #include<iostream> #include<cstdlib> #include<algorithm> #include<ctime> #include<cctype> #include<cmath> #include<string> #include<cstring> #include<stack> #include<queue> #include<list> #include<vector> #include<map> #include<set> #define sqr(x) ((x)*(x)) #define LL long long #define itn int #define INF 0x3f3f3f3f #define PI 3.1415926535897932384626 #define eps 1e-10 #define maxm #define maxn using namespace std; class BishopMove { public: int howManyMoves(int r1, int c1, int r2, int c2) { if (r1==r2 && c1==c2) return 0; if (((r1+c1)&1) == ((r2+c2)&1)) { if (abs(r1-r2)==abs(c1-c2)) return 1; return 2; } return -1; } }; int main() { #ifndef ONLINE_JUDGE freopen("/home/fcbruce/文档/code/t","r",stdin); #endif // ONLINE_JUDGE return 0; }
500-point problem
给出一个括号序列,X可被括号替换,问这串序列是否可能合法。因为当时没看见X的数量不超过5就用了区间DP,有一处下标居然没控制好结果RE。。。。其实可以用DFS求出所有可能的序列,然后用栈判断;区间DP只要求出对这段序列最少加多少括号使其合法就行,如果为0就是合法的,要注意对匹配括号的判断。
#include<cstdio> #include<iostream> #include<cstdlib> #include<algorithm> #include<ctime> #include<cctype> #include<cmath> #include<string> #include<cstring> #include<stack> #include<queue> #include<list> #include<vector> #include<map> #include<set> #define sqr(x) ((x)*(x)) #define LL long long #define itn int #define INF 0x3f3f3f3f #define PI 3.1415926535897932384626 #define eps 1e-10 #define maxm #define maxn using namespace std; class BracketExpressions { public: bool check(char x,char y) { if (x=='(' && y==')' || x=='['&& y==']' ||x=='{' && y=='}') return true; if (x=='X' && (y==']' || y=='}' || y==')' || y=='X')) return true; if (y=='X' && (x=='(' || x=='[' || x=='{')) return true; return false; } string ifPossible(string str) { int l=str.size(); int dp[60][60]; memset(dp,0,sizeof dp); for(int i = 0; i<l; i++) { dp[i][i] = 1; } for (int m=1;m<l;m++) { for (int i=0;i<l;i++) { int j=i+m; if (j>=l) break; dp[i][j]=INF; if (check(str[i],str[j])) dp[i][j]=min(dp[i][j],dp[i+1][j-1]); for (int k=i;k<j;k++) { dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]); } } } if (dp[0][l-1]==0) return "possible"; else return "impossible"; } }; int main() { #ifndef ONLINE_JUDGE freopen("/home/fcbruce/文档/code/t","r",stdin); #endif // ONLINE_JUDGE return 0; }
1000-point problem
时间不够,比赛的时候没来得及敲完。。。。。
题意:
给出一个有n个元素的集合E={ x | 0<=x<n , x为整数 },和一段序列f={ xi | 0<=xi,i<n },对于集合E的子集S,有任意i属于S,f[i]=xi 也属于S,问这样的子集有多少个。
分析:
这其实是个图论。
对于每一个i,都对应一个f[i]=xi,如果我取i,那我必定也要取f[i]=xi,即i依赖于f[i]=xi。于是建立有向边i---->f[i]=xi;对于图中的每个强联通分量,这个分量中的所有点一定是同时取的。我们可以进行强联通缩点(tarjan),剩下的DAG中每个点都有取和不取两种关系。应用乘法原理和加法原理,反向建图后通过树形DP求得最后的方案数:对于节点u,取这个节点的方案数是它所有子节点的方案数相乘,不取这个节点的方案数为1。
#include<cstdio> #include<iostream> #include<cstdlib> #include<algorithm> #include<ctime> #include<cctype> #include<cmath> #include<string> #include<cstring> #include<stack> #include<queue> #include<list> #include<vector> #include<map> #include<set> #define sqr(x) ((x)*(x)) #define LL long long #define itn int #define INF 0x3f3f3f3f #define PI 3.1415926535897932384626 #define eps 1e-10 #define maxm 555555 #define maxn 55 using namespace std; int fir[maxn]; int u[maxm],v[maxm],nex[maxm]; long long w[maxn]; int n; int pre[maxn],low[maxn],sccno[maxn]; int st[maxn],top; int dfs_clock,scc_cnt; int deg[maxn]; void tarjan_dfs(int _u) { pre[_u]=low[_u]=++dfs_clock; st[++top]=_u; for (int e=fir[_u];e!=-1;e=nex[e]) { int _v=v[e]; if (pre[_v]==0) { tarjan_dfs(_v); low[_u]=min(low[_u],low[_v]); } else { if (sccno[_v]==0) low[_u]=min(low[_u],pre[_v]); } } if (low[_u]==pre[_u]) { scc_cnt++; while (true) { int x=st[top--]; sccno[x]=scc_cnt; if (x==_u) break; } } } void find_scc() { dfs_clock=scc_cnt=0; top=-1; memset(sccno,0,sizeof sccno); memset(pre,0,sizeof pre); for (int i=0;i<n;i++) { if (pre[i]==0) tarjan_dfs(i); } } long long dfs(int _u) { long long temp=1; for (int e=fir[_u];~e;e=nex[e]) { temp*=dfs(v[e]); } return temp+1; } class InvariantSets { public: long long countSets(vector <int> f) { n=f.size(); memset(fir,-1,sizeof fir); for (int i=0;i<n;i++) { u[i]=i;v[i]=f[i]; nex[i]=fir[i];fir[i]=i; } find_scc(); memset(fir,-1,sizeof fir); memset(deg,0,sizeof deg); int e=0; for (int i=0;i<n;i++) { if (sccno[u[i]]==sccno[v[i]]) continue; u[e]=sccno[u[i]];v[e]=sccno[v[i]]; swap(u[e],v[e]); nex[e]=fir[u[e]]; deg[v[e]]++; fir[u[e]]=e++; } for (int i=1;i<=scc_cnt;i++) { if (deg[i]==0) { u[e]=i;v[e]=0; swap(u[e],v[e]); nex[e]=fir[u[e]]; fir[u[e]]=e++; } } return dfs(0)-1; } }; int main() { #ifndef ONLINE_JUDGE freopen("/home/fcbruce/文档/code/t","r",stdin); #endif // ONLINE_JUDGE InvariantSets a; itn x,y; while (~scanf("%d",&x)) { vector <int> v; for (int i=0;i<x;i++) { scanf("%d",&y); v.push_back(y); } printf("%lld\n",a.countSets(v)); } return 0; }
Topcoder SRM 628 DIV 2