A - Cookies
题目大意是现在有N袋的饼干,要求拿走一带,剩下的所有数量是偶数,问有多少种拿法。
很简单,直接统计当前饼干总数和每袋是奇数和偶数的个数。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <string>
#include <map>
#include <queue>
#include <vector>
using namespace std;
int main()
{
int n;
while(scanf("%d", &n) != EOF){
int i;
int t, s, odd, even;
s = odd = even = 0;
for(i = 0; i < n; ++i){
scanf("%d", &t);
s += t;
if(t & 1){
odd++;
}
else{
even++;
}
}
if(s & 1){
printf("%d\n",odd);
}
else{
printf("%d\n",even);
}
}
return 0;
}
B - Students and Shoelaces
有N个孩子,他们非常顽皮,他们的鞋带缠在一起,现在有M对关系,现在老师要把那些只和另外一个孩子的鞋带缠在一起的孩子们移开,问需要移动多少轮。
先把有缠一起的孩子连一条边,无向的,类似拓扑排序,每次去掉度为1的孩子。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <string>
#include <map>
#include <queue>
#include <vector>
using namespace std;
int mat[105][105];
int d[105];
struct node{
int d;
int id;
friend bool operator < (node a, node b){
return a.d > b.d;
}
}tt;
queue<int> Q;
int main()
{
int n, m;
while(scanf("%d %d", &n, &m) != EOF){
int i, j;
int a, b;
memset(mat, 0, sizeof(mat));
memset(d, 0, sizeof(d));
for(i = 0; i < m; ++i){
scanf("%d %d", &a, &b);
mat[a][b] = mat[b][a] = 1;
d[a]++;
d[b]++;
}
int ans = 0;
while(1){
for(i = 1; i <= n; ++i){
if(d[i] == 1){
Q.push(i);
}
}
if(Q.empty()){
break;
}
while(!Q.empty()){
j = Q.front();
d[j]--;
Q.pop();
for(i = 1; i <= n; ++i){
if(mat[j][i] || mat[i][j]){
mat[i][j] = mat[j][i] = 0;
d[i]--;
}
}
}
ans++;
}
printf("%d\n", ans);
}
return 0;
}
C - Statues
题目是有一幅图,右上角是A所在的位置,左下角是M所在的位置,现在有若干个S,当前是M先走,可以走八方向,接着所有的S都向下走一格,若S碰到M,则LOSE,若M能到达A,则WIN。
暴力模拟。我采用了一个很卑鄙的手段,地图最多只有八种情况,所以直接模拟8步的地图,然后M从左下角开始走,若能走到8步之后,则WIN,否则LOSE。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <string>
#include <map>
#include <queue>
#include <vector>
using namespace std;
char mat[9][9][9];
int hash[9][2] = {{0,0},{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1}};
bool flag;
void dfs(int x, int y, int k)
{
if(flag || k == 8){
flag = 1;
return ;
}
int i, tx, ty;
for(i = 0; i < 9; ++i){
tx = x + hash[i][0];
ty = y + hash[i][1];
if(tx >= 0 && tx < 8 && ty >= 0 && ty < 8){
if(mat[k][tx][ty] != 'S' && mat[k + 1][tx][ty] != 'S'){
dfs(tx, ty, k + 1);
}
}
}
}
int main()
{
while(cin>>mat[0][0]){
int i, j, k;
for(i = 1; i < 8; ++i){
cin>>mat[0][i];
}
for(k = 1; k <= 8; ++k){
for(i = 0; i < 8; ++i){
for(j = 0; j < 8; ++j){
if(i == 0){
mat[k][i][j] = '.';
continue;
}
if(mat[k - 1][i - 1][j] == 'S'){
mat[k][i][j] = 'S';
}
else{
mat[k][i][j] = '.';
}
}
}
}
flag = 0;
dfs(7,0,0);
if(flag){
puts("WIN");
}
else{
puts("LOSE");
}
}
return 0;
}
D - String
有一个最大长度为10^5次的串,要输出逻辑第K大的子串。
考虑到K只有10^5,所以模拟每步。用priority_queue。把长度为1个子串放到队列,每次都更新当前最小的串。K次之后就是答案。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <queue>
using namespace std;
char a[100005];
struct node{
int idx;
string x;
bool friend operator < (node a, node b){
return a.x > b.x;
}
}tt;
priority_queue<node> Q;
int main()
{
while(gets(a)){
int k, i;
long long len;
scanf("%d%*c", &k);
len = (long long)strlen(a);
while(!Q.empty()){
Q.pop();
}
if(2LL * k > len * (len + 1)){
puts("No such line.");
continue;
}
for(i = 0; i < len; ++i){
tt.x = a[i];
tt.idx = i;
Q.push(tt);
}
while(k != 1){
tt = Q.top();
Q.pop();
if(tt.idx + 1 != len){
tt.x += a[++tt.idx];
Q.push(tt);
}
--k;
}
cout<<Q.top().x<<endl;
}
return 0;
}
E - Games with Rectangle
给你一个n*m的长方形,你要框出k个长方形,且每次框的长方形都要在上一个的里面(并且与上一个无公共边),问有几种不同的框法(n,m,k<=1000)
显然这题的行和列是相互独立的,所以可以分开处理,然后用乘法原理即可
记f[i][j]表示取i次之后长度为j的方案数,则易得出
f[i][j]=f[i-1][j-2]+2*f[i-1][j-3]+…+(n-1)*f[i-1][j-n]
不过这是n^3,需要做一个优化,设
s=f[i-1][j-2]+f[i-1][j-3]+…+f[i-1][j-n];
则上述方程可化为:f[i][j]=s+f[i][j-1];
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <queue>
using namespace std;
long long f[1005][1005];
const long long Mod = 1000000007;
int main()
{
int n, m, k;
while(scanf("%d %d %d", &n, &m, &k) != EOF){
int i, j;
int limit = n>m?n:m;
int sum;
for(i = 1; i <= 1000; ++i)
f[0][i] = 1;
for(i = 1; i <= k; ++i){
sum = 0;
for(j = 3; j <= limit; ++j){
sum = (sum + f[i - 1][j - 2]) % Mod;
f[i][j] = (sum + f[i][j - 1]) % Mod;
}
}
printf("%lld\n", (f[k][n] * f[k][m]) % Mod);
}
return 0;
}
F - Numbers
给定一个序列,能否构成一个环,并且相邻的两个数的差只能为1。
想了一会,感觉n为奇数肯定不可以,还有就是,若这个环存在的话,只要按照规矩放,就一定能放好。所以我按照贪心的想法,把小的能放则放的原则,进行模拟就好了。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <queue>
#include <map>
using namespace std;
map<int, int> M;
map<int, int>::iterator it;
struct node{
int a,b;
}l[100005];
int main()
{
int n;
while(scanf("%d", &n) != EOF){
int i, j;
M.clear();
for(i = 0; i < n; ++i){
scanf("%d", &j);
if(M.find(j) == M.end()){
M[j] = 1;
}
else{
M[j]++;
}
}
if(n & 1){
puts("NO");
continue;
}
int len = 0;
for(it = M.begin(); it != M.end(); ++it){
l[len].a = it->first;
l[len++].b = it->second;
}
for(i = 1; i < len - 1; ++i){
if(l[i - 1].a + 1 == l[i].a && l[i - 1].b < l[i].b){
l[i].b = l[i].b - l[i - 1].b;
}
else{
puts("NO");
break;
}
}
if(i == len - 1){
if(l[i].b == l[i - 1].b && l[i].a == l[i - 1].a + 1){
puts("YES");
}
else{
puts("NO");
}
}
}
return 0;
}