福州大学第十一届程序设计竞赛
Contest Finished!
Tag | Pro.ID | Problem Title | Ratio(AC/Submit) |
---|---|---|---|
1 | 大王叫我来巡山呐 | 80.31%(261/325) | |
2 | 防守阵地 I | 23.48%(193/822) | |
3 | shadow | 13.23%(97/733) | |
4 | 花生的序列 | 12.07%(21/174) | |
5 | 防守阵地 II | 14.98%(68/454) | |
6 | 巡了南山我巡北山 | 0.00%(0/45) | |
7 | Nostop | 20.79%(21/101) | |
8 | 卷福的难题 | 10.00%(1/10) |
本来打算当作组队赛来做的,结果队友有足球赛,还有一个有党校。。只剩下我一个人单挑了。 @.@ 还好不是很难,不然就被虐翻了。。整体来说题目比较简单,应该本来就是作为个人赛准备的。。
A题签到题
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define LL long long
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
const int maxn = 5;
const int INF = 0x3f3f3f3f;
int main()
{
int n;
while(scanf("%d", &n) != EOF)
{
int ans = n / 7 * 2;
if(n % 7 == 6) ans ++;
printf("%d\n", ans);
}
}
B题观察式子转移,就可以很容易发现端倪了。。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define LL long long
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
const int maxn = 1001000;
const int INF = 0x3f3f3f3f;
int a[maxn];
int main()
{
int n, m;
while(scanf("%d%d", &n, &m) != EOF)
{
int ans = 0, tot = 0, sum = 0;
for(int i = 1; i <= m; i ++)
{
scanf("%d", &a[i]);
sum += a[i];
tot += i*a[i];
}
ans = tot;
for(int i = m + 1; i <= n; i ++)
{
scanf("%d", &a[i]);
tot -= sum;
sum -= a[i - m];
sum += a[i];
tot += a[i] * m;
ans = max(ans, tot);
}
printf("%d\n", ans);
}
}
C题是比较简单的树dp吧,只需要看孩子和本身有没有士兵,有的话当前点肯定会被消灭。OJ比较奇特,递归会爆栈,用vector会超时。。不幸的是两种情况我都遇到了。。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define LL long long
#define MP make_pair
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
const int maxn = 100100;
const int INF = 0x3f3f3f3f;
int arm[maxn];
bool hav[maxn];
struct Edge
{
int u, v;
}E[maxn*2];
int fir[maxn], nxt[maxn*2], tot = 0;
LL d[maxn];
void AddEdge(int u, int v)
{
E[tot].u = u, E[tot].v = v;
nxt[tot] = fir[u], fir[u] = tot ++;
}
LL dfs()
{
stack<pair<int, int> > S;
CLR(d, 0);
S.push(MP(1, 0));
int cnt = 0;
while(!S.empty())
{
int u = S.top().first, fa = S.top().second;
if(fir[u] == -1)
{
if(hav[u]) hav[fa] = 1, d[fa] += d[u] + arm[u];
S.pop();
}
else
{
int v = E[fir[u]].v;
fir[u] = nxt[fir[u]];
if(v == fa) continue;
S.push(MP(v, u));
}
}
return d[1];
}
int main()
{
int n, k;
while(scanf("%d%d", &n, &k) != EOF)
{
for(int i = 1; i <= n; i ++)
{
scanf("%d", &arm[i]);
}
CLR(hav, 0);CLR(fir, -1); tot = 0;
for(int i = 0; i < k; i ++)
{
int u; scanf("%d", &u);
hav[u] = 1;
}
for(int i = 1; i < n; i ++)
{
int u, v;
scanf("%d%d", &u, &v);
AddEdge(u, v);
AddEdge(v, u);
}
printf("%lld\n", dfs());
}
}
D题算是一道dp吧,dp[i][j],表示到第i为为止,有j个属于第一个串,因为串的特殊性(WBWBWB),所以很容易判断当前位置的字母满足的情况。比如当前j为奇数,那么j后面肯定只能接B。。。就这样。。。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define LL long long
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
const int maxn = 10100;
const int INF = 0x3f3f3f3f;
const int MOD = 1000000007;
char ch[maxn];
int dp[2][3300];
int main()
{
int T, n;
scanf("%d", &T);
while(T --)
{
scanf("%d%s", &n, ch);
CLR(dp, 0);
dp[0][0] = 1;
for(int i = 0, j = 1; i < n * 2; i ++, j ++)
{
CLR(dp[j&1], 0);
if(ch[i] == 'B')
{
for(int k = 0; k <= n; k ++)
{
if(k&1) dp[j&1][k+1] = (dp[j&1][k+1] + dp[i&1][k]) % MOD;
if((i-k)&1) dp[j&1][k] = (dp[j&1][k] + dp[i&1][k]) % MOD;
}
}
else
{
for(int k = 0; k <= n; k ++)
{
if((k&1) == 0) dp[j&1][k+1] = (dp[j&1][k+1] + dp[i&1][k]) % MOD;
if(((i-k)&1) == 0) dp[j&1][k] = (dp[j&1][k] + dp[i&1][k]) % MOD;
}
}
}
printf("%d\n", dp[0][n]);
}
}
E裸线段树区间更新,区间查询,只要你不想那么多,就可以直接A掉。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define LL long long
#define CLR(a, b) memset(a, b, sizeof(a))
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
using namespace std;
const int maxn = 100100;
const int INF = 0x3f3f3f3f;
int add[maxn<<2];
int sum[maxn<<2];
void PushUp(int rt)
{
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void PushDown(int rt,int m)
{
if (add[rt])
{
add[rt<<1] += add[rt];
add[rt<<1|1] += add[rt];
sum[rt<<1] += add[rt] * (m - (m >> 1));
sum[rt<<1|1] += add[rt] * (m >> 1);
add[rt] = 0;
}
}
void build(int l,int r,int rt)
{
add[rt] = 0;
if (l == r)
{
scanf("%d",&sum[rt]);
return ;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
PushUp(rt);
}
void update(int L,int R,int c,int l,int r,int rt)
{
if (L <= l && r <= R)
{
add[rt] += c;
sum[rt] += c * (r - l + 1);
return ;
}
PushDown(rt , r - l + 1);
int m = (l + r) >> 1;
if (L <= m) update(L , R , c , lson);
if (m < R) update(L , R , c , rson);
PushUp(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if (L <= l && r <= R)
{
return sum[rt];
}
PushDown(rt , r - l + 1);
int m = (l + r) >> 1;
LL ret = 0;
if (L <= m) ret += query(L , R , lson);
if (m < R) ret += query(L , R , rson);
return ret;
}
int main()
{
int n, m, q;
while(scanf("%d%d%d", &n, &m, &q) != EOF)
{
build(1, n, 1);
for(int i = 0; i < q; i ++)
{
int x; scanf("%d", &x);
printf("%d\n", query(x, x + m - 1, 1, n, 1));
update(x, x + m - 1, -1, 1, n, 1);
}
}
}
F应该是搜索吧。。。感觉无从下手,罪过。。。大致思路应该是判断是否是子串,然后在进行加字符,copy操作吧。。。我猜的。。
G题这种题第一次见到,感觉自己YY出来还是很高兴的!就是用矩阵来表示走K步之后的各个点对到达所需要的最小花费。这样的话,我们就可以用初始矩阵(表示的是1步到达的情况)不断更新,来获得走2步,走3步的到达情况。。这样的话思路就很明确了。因为题目数据比较大,我们直接用快速幂更新就可以了。(应该很容易想到这些更新是满足结合率的吧)。我还是觉得看代码清楚些。。这个OJ很个性,用lld,wa了无数次,改成cin,cout才过。。。=.=!!
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define LL long long
#define MP make_pair
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
const int maxn = 55;
const LL INF = 1ll << 60;
struct Matrix
{
LL m[maxn][maxn];
}sol, pre;
int n;
Matrix Add(Matrix a, Matrix b)
{
Matrix ret;
for(int i = 1; i <= n; i ++)
{
for(int j = 1; j <= n; j ++)
{
ret.m[i][j] = INF;
LL& tmp = ret.m[i][j];
for(int k = 1; k <= n; k ++)
{
tmp = min(tmp, a.m[i][k] + b.m[k][j]);
}
}
}
return ret;
}
Matrix Mul(Matrix a, int n)
{
Matrix ret;
bool flag = false;
while(n)
{
if(n & 1)
{
if(flag) ret = Add(ret, a);
else ret = a;
flag = true;
}
a = Add(a, a);
n >>= 1;
}
return ret;
}
void pt(Matrix sol)
{
for(int i = 1; i <= n; i ++)
{
for(int j = 1; j <= n; j ++)
printf("%lld ", sol.m[i][j]);
puts("");
}
}
int main()
{
int h, k, T;
scanf("%d", &T);
while(T --)
{
scanf("%d%d%d", &n, &h, &k);
for(int i = 1; i <= n; i ++)
{
for(int j = 1; j <= n; j ++)
sol.m[i][j] = INF;
}
for(int i = 0; i < h; i ++)
{
int u, v;LL c;
scanf("%d%d", &u, &v); cin >> c;
sol.m[u][v] = min(sol.m[u][v], c);
}
sol = Mul(sol, k);
if(sol.m[1][n] == INF) puts("-1");
else cout << sol.m[1][n] << endl;
//printf("%lld\n", sol.m[1][n]);
}
}
H题完全没想法,最后绝杀的那个人真厉害,ORZ~~