Codeforces Round #363 (Div. 2)
/*
C :
题意 :一个人有 N 天假期,他可以选择写题 ,也可以选择锻炼,也可以选择休息 。 但不能连续两天做同一件事 ,休息除外。 写题需要当天有比赛, 锻炼需要当天体育馆开放。 用数字表示每一天的情况。 0 :无比赛,体育馆也不开放 ,即只能休息 1 : 体育馆开放,没有比赛 ;即可以锻炼 2 : 有比赛,体育馆不开放 ;即可以写题 3 :体育馆开放,有比赛 ;即锻炼 写题二选一 给出每一天的情况,问他至少可以休息几天。 解题:DP d[i][j]表示第 i 天 做了 j 事 的休息天数。( j =0 表示休息,j = 1表示锻炼,j = 2表示写题) 最后答案就是 d[n][i]中最小的那个 吐槽: 照理说想出状态 应该差不多了,但我还是憋不出去看题解了= =弱菜少年,希望集训完能长进点 */ #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #define INF 0x3f3f3f3f using namespace std; const int maxn = 110; int n,a[maxn],d[maxn][3]; int main() { scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); for(int j=0;j<3;j++) d[i][j] = INF; } int ans = maxn; for(int i=1;i<=n;i++){ if(a[i] == 0) d[i][0] = min(d[i-1][0], min(d[i-1][1], d[i-1][2])) + 1; if(a[i] == 1){ d[i][0] = min(d[i-1][0], min(d[i-1][1], d[i-1][2])) + 1; d[i][1] = min(d[i-1][0], d[i-1][2]); } if(a[i] == 2){ d[i][0] = min(d[i-1][0], min(d[i-1][1], d[i-1][2])) + 1; d[i][2] = min(d[i-1][0], d[i-1][1]); } if(a[i] == 3){ d[i][0] = min(d[i-1][0], min(d[i-1][1], d[i-1][2])) + 1; d[i][1] = min(d[i-1][0], d[i-1][2]); d[i][2] = min(d[i-1][0], d[i-1][1]); } } for(int i=0;i<3;i++) ans = min(ans,d[n][i]); cout<<ans<<endl; return 0; }
/* B 题意: 有一个 n*m 的矩形, '.' 表示空地 '*' 表示障碍。 你有一颗炸弹,爆炸时可以消除 炸弹所在行 和 所在列的所有障碍。 给出 n m 和矩阵。 问 能否 把炸弹放在一个地方使所有障碍消除。炸弹可以放在矩阵任何位置 。 解题: 记录每个点所在行和列有多少个障碍。 再整个矩阵扫一遍,若当前点所在行列的障碍总数相加等于整个矩阵的障碍总数,就输出答案,否则不行。 比赛时没做出来 つ﹏? 坑了我好久..... */ #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> using namespace std; const int maxn = 1010; int main() { int n,m,cnt=0; int x[maxn],y[maxn]; char str[maxn][maxn]; memset(x,0,sizeof(x)); memset(y,0,sizeof(y)); cin>>n>>m; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cin>>str[i][j]; if(str[i][j] == '*'){ x[i]++; y[j]++; cnt++; } } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(( x[i] + y[j] - (str[i][j] == '*') ) == cnt){ printf("YES\n%d %d\n",i,j); return 0; } } } printf("NO\n"); return 0; }
/* D 题意: 给出一个长度为 N 的序列 P,其中 Pi 为 第 i 个点的父节点,根节点的父节点是他自己。 注: 题目给出的序列不一定有根节点。 问要修改多少个点可以使这个序列变成一棵多叉树。 参考了题解。 解题: 要使这个序列形成一棵树,那么只能有一个根节点。 而根节点的父节点是他自己,这样就有了一个环。 也就是说这个图里只能有一个环。 如果存在多个环,就要把他拆开,统一接到一个根节点上。 在输入的时候统计有几个根节点,用编号最大的那个作为统一的根节点。 使用 DFS 判环,遇到环时,如果有确认的根节点,那么就给它接上去, 如果没有, 就让他指向自己。 最后统计答案,有多少个节点的父节点与自己原来的父节点不一样就是改变了多少个节点 。 然后直接输出数组。 */ #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> using namespace std; const int maxn = 200010; int p[maxn],a[maxn],vis[maxn],cnt=0,mx=0; void dfs(int x) { if(!vis[x]){ vis[x] = 1; dfs(p[x]); } else if(vis[x]==1){ if(cnt) a[x] = mx; else{ a[x] = x; cnt++; mx = x; } vis[x] = 2; return; } vis[x] = 2; } int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&p[i]); a[i] = p[i]; if(i == p[i]){ cnt++; mx = max(mx,p[i]); } } for(int i=1;i<=n;i++) dfs(i); int ans =0; for(int i=1;i<=n;i++){ if(a[i] != p[i]) ans ++; } printf("%d\n",ans); cout<<a[1]; for(int i=2;i<=n;i++) printf(" %d",a[i]); cout<<endl; return 0; }