最近才重新做的,还是太挫。。
A:Boredom
类型:一个简单的dp(不过因为long long 的问题结果wa了好多发)
sum[i] :表示选取当前 i 值;
sum2[i] :表示不选当前 i 值;
转移方程:
sum[i] = sum2[i-1]+a[i]*i;
sum2[i] = max(sum[i-1], sum2[i-1]);
B:A Lot of Games
类型:dp+字典树
参考链接:http://www.cnblogs.com/LJ-blog/p/3904755.html
can_win数组:下一步由先手走,能否赢。能赢则为1,不能赢为0;
can_lose数组:下一步由先手走,能否输。能输则为1,不能输则为0;
应该从叶子节点往根推,可以肯定的是,叶子节点can_win为0,can_lose为1;
C:Civilization
类型:并查集+树的直径
一开始先根据所给的m条边建好图(邻接表),当然点与点的联系也要添加到并查集当中。
然后根据所建的图求出所有树的直径(再开一个数组保存,保存直径的数组的下标是该树并查集的根节点 )。
查询:
操作1 直接find(x)寻找到x所在的树的根节点。
操作2 要让每次合并的树的直径尽量小,肯定是:树1的半径+树2的半径 + 1,树1的直径,树2的直径中的最大值。(半径往上取整)
AC代码:
A:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <queue>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 5;
const int INF = 0x3f3f3f3f;
int a[MAXN], n, mark[MAXN];
ll sum[MAXN], sum2[MAXN];
int main()
{
while(scanf("%d", &n) != EOF)
{
int tmp;
memset(mark, 0, sizeof(mark));
memset(a, 0, sizeof(a));
memset(sum, 0, sizeof(sum));
memset(sum2, 0, sizeof(sum2));
int maxn = -1, minn = INF;
for(int i = 0;i < n; i++)
{
scanf("%d", &tmp);
a[tmp]++;
maxn = max(maxn, tmp);
minn = min(minn, tmp);
}
sum[minn] = (ll)a[minn]*minn;
for(int i = minn+1;i <= maxn; i++)
{
if(a[i] == 0)
{
sum[i] = sum2[i] = max(sum[i-1],sum2[i-1]);
continue;
}
sum[i] = sum2[i-1]+(ll)a[i]*i;
sum2[i] = max(sum[i-1], sum2[i-1]);
//cout<<"sum[i] = "<<sum[i]<<endl;
//cout<<"sum2[i] = "<<sum2[i]<<endl;
}
cout<<max(sum[maxn], sum2[maxn])<<endl;
}
return 0;
}
B:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
using namespace std;
const int MAXN = 1e5+5;
const int INF = 0x3f3f3f3f;
const int SIGMA_SIZE = 30;
typedef long long ll;
char str[MAXN];
int ch[MAXN][SIGMA_SIZE], sz;
int can_lose[MAXN], can_win[MAXN];
int insert(char *s)
{
int len = strlen(s);
int u = 0;
for(int i = 0;i < len; i++)
{
int c = s[i] - 'a';
if(!ch[u][c]) ch[u][c] = ++sz;
u = ch[u][c];
}
}
void dfs(int u)
{
bool hav = false;
for(int i = 0;i < 26; i++)
{
if(ch[u][i])
{
dfs(ch[u][i]);
hav = true;
}
}
if(!hav)
{
can_lose[u] = 1;
can_win[u] = 0;
return;
}
for(int i = 0;i < 26; i++)
{
int& v = ch[u][i];
if(v != 0 && can_lose[v] == 0) can_lose[u] = 1;
if(v != 0 && can_win[v] == 0) can_win[u] = 1;
}
}
int n, k;
int main()
{
scanf("%d%d", &n, &k);
sz = 0;
for(int i = 0;i < n; i++)
{
scanf("%s", str);
insert(str);
}
dfs(0);
//test
if((k%2 && can_win[0]&&!can_lose[0]) || (can_win[0]&&can_lose[0]))
puts("First");
else
puts("Second");
return 0;
}
C:
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <vector>
#include <iostream>
using namespace std;
const int MAXN = 6*1e5 + 5;
const int INF = 0x3f3f3f3f;
int n, m, f;
int bcj[MAXN], val[MAXN];
vector <int> edge[MAXN];
bool vis[MAXN];
void init()
{
for(int i = 0;i <= n ; i++)
bcj[i] = i, edge[i].clear();
memset(val, 0, sizeof(val));
memset(vis, false, sizeof(vis));
}
int find(int u)
{
return bcj[u] == u ? u : bcj[u] = find(bcj[u]);
}
int tu;
int dfs(int u, int len)
{
int val1 = 0, val2 = 0, tmp = 0, ret = len, noname;
vis[u] = true;
for(int i = 0;i < edge[u].size(); i++)
{
int v = edge[u][i];
if(vis[v]) continue;
noname = dfs(v, len+1);
tmp = noname - len;
ret = max(ret, noname);
if(tmp > val1) swap(val1, val2), val1 = tmp;
else if(tmp > val2) val2 = tmp;
val[tu] = max(val[tu], val1+val2);
}
return ret;
}
int main()
{
while(scanf("%d%d%d", &n, &m, &f) != EOF)
{
init();
int x, y;
for(int i = 0;i < m; i++)
{
scanf("%d%d",&x, &y);
edge[x].push_back(y);
edge[y].push_back(x);
x = find(x), y = find(y);
bcj[x] = y;
}
//dfs
//
for(int i = 1;i <= n; i++)
{
if(!vis[find(i)]) tu = find(i), dfs(tu, 0);
}
int co;
for(int i = 0;i < f; i++)
{
scanf("%d", &co);
if(co == 1)
{
scanf("%d", &x);
//cout<<find(x)<<endl;
printf("%d\n", val[find(x)]);
}
else
{
scanf("%d%d", &x, &y);
x = find(x), y = find(y);
if(x == y) continue;
int len1 = val[x]%2 == 0 ? val[x]/2 : val[x]/2+1;
int len2 = val[y]%2 == 0 ? val[y]/2 : val[y]/2+1;
val[x] = val[y] = max(max(val[x],val[y]), len1+len2+1);
bcj[y] = x;
}
}
}
return 0;
}