problem A. Quiz
YY一下,贪心就行。
对于F[N] = 2*( F[N - 1] + K)的计算,可以:
1、推出等比数列公式,然后用整数快速幂。
2、矩阵快速幂计算
3、F[N] + 2*K = 2 * (F[N - 1] + 2*K)。设a[N] = F[N] + 2*K,转换递归式,然后整数快速幂。
都可以求解。
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
using namespace std;
#define llg long long
template<typename T> inline void checkMin(T& a, T b) { if (a > b) a = b; }
template<typename T> inline void checkMax(T& a, T b) { if (a < b) a = b; }
template<class T> inline T Min(T x,T y){return (x>y?y:x);}
template<class T> inline T Max(T x,T y){return (x<y?y:x);}
llg mod = 1000000009;
llg n,m,k;
llg ans;
llg quickpow(llg a,llg b)
{
llg ans = 1;
while(b)
{
if(b&1) ans = (ans * a)%mod;
a = (a * a)%mod;
b = b>>1;
}
return ans;
}
int main()
{
cin>>n>>m>>k;
ans = 0;
llg wa = n - m;
llg r = (n - m) * k;
if(r >= n)
ans = m;
else
{
llg nn = n - r;
llg a = nn / k;
llg b = nn % k;
ans = ((quickpow(2,a + 1) - 2 + mod)%mod)*k%mod;
ans += b + wa*(k - 1)%mod;
ans %= mod;
}
cout<<ans<<endl;
return 0;
}
problem B. Book of Evil
赛后才过的,很明显的树形DP。
推荐可以先做弱化版本hdu 2196。
思想关键在于对dpdown,dpup的理解。
第一个dfs1:父亲问儿子们:儿子们,从你们往下走,碰到最远的evil有多远啊?从各个儿子回答中,得出dpdown[ father ][ 0 ]即自己距离evil最远的距离,dpdown[ father ][ 1]即自己距离evil次最远的距离。
第二个dfs2:儿子跟父亲说:父亲,我往你这边走,可以到达evil的最远距离是多少啊?更新dpup[i]。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define maxn 100010
struct tree
{
vector<int> child;
}node[maxn];
int n,m,d;
int dpdown[maxn][2];/*0 is longest 1 is second*/
int dpup[maxn];
int next[maxn];/*longest distance next*/
bool vis[maxn];
bool evil[maxn];
void addedge(int x,int y)
{
node[x].child.push_back(y);
node[y].child.push_back(x);
}
int mymax(int x,int y)
{return x>y?x:y;}
void dfs1(int fa,int now)
{
vis[now] = true;
dpdown[now][0] = dpdown[now][1] = -1;
dpup[now] = -1;
next[now] = 0;
if(evil[now]) dpdown[now][0] = 0;
for(int i = 0;i < node[now].child.size();i++)
{
int son = node[now].child[i];
if(vis[son] || son == fa) continue;
dfs1(now,son);
if(dpdown[son][0] >= 0)
{/*除去-1*/
if(dpdown[son][0] + 1 >= dpdown[now][0])
{
dpdown[now][1] = mymax(dpdown[now][0],dpdown[now][1]);
dpdown[now][0] = dpdown[son][0] + 1;
next[now] = son;
}
else
{
dpdown[now][1] = mymax(dpdown[son][0] + 1,dpdown[now][1]);
}
}
}
}
void dfs2(int fa,int now)
{
for(int i = 0;i < node[now].child.size();i++)
{
int son = node[now].child[i];
if(son == fa) continue;
if(dpup[now] >= 0)
dpup[son] = dpup[now] + 1;
if(next[now] != son && dpdown[now][0] >= 0)
{
dpup[son] = mymax(dpup[son],dpdown[now][0] + 1);
}
else if(dpdown[now][1] >= 0)
{
dpup[son] = mymax(dpup[son],dpdown[now][1] + 1);
}
dfs2(now,son);
}
}
int main()
{
scanf("%d %d %d",&n,&m,&d);
for(int i = 1;i <= m;i++)
{
int x;
scanf("%d",&x);
evil[x] = true;
}
for(int i = 1;i <= n - 1;i++)
{
int x,y;
scanf("%d %d",&x,&y);
addedge(x,y);
}
dfs1(-1,1);
dfs2(-1,1);
int ans = 0;
for(int i = 1;i <= n;i++)
{
if(dpdown[i][0] <= d && dpup[i] <= d)
ans++;
}
printf("%d\n",ans);
return 0;
}
problem C. Divisor Tree
暴力枚举树。。
每个数字有这样几个去向:
1、a1作为a2的一个因子,即“有father的数字"这一类型。
2、a1不作为任何数字的因子,那么可以将这些类型的数字:一、素因子个数直接加到答案,二、最后合并为根,一个就不需要合并了。
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <limits.h>
using namespace std;
#define llg long long
template<typename T> inline void checkMin(T& a, T b) { if (a > b) a = b; }
template<typename T> inline void checkMax(T& a, T b) { if (a < b) a = b; }
template<class T> inline T Min(T x,T y){return (x>y?y:x);}
template<class T> inline T Max(T x,T y){return (x<y?y:x);}
#define maxn 20
llg a[maxn],ta[maxn];
int fa[maxn],cnt[maxn];
int n;
int ans = INT_MAX;
void ok()
{
int twotree = 0;
int tans = 0;
for(int i = 1;i <= n;i++)
{
if(fa[i] == 0)
{
twotree++;
tans += cnt[i];
}
if(cnt[i] == 1)/*不要算自己*/
tans--;
}
tans += n;
if(twotree >= 2) tans++;
if(tans < ans) ans = tans;
}
void dfs(int now)
{
if(now == n) {ok();return ;}
for(int i = now+1;i <= n;i++)
{
if(ta[i]%a[now] == 0)
{/*被用来当作因子*/
ta[i] /= a[now];
fa[now] = i;
dfs(now + 1);
ta[i] *= a[now];
}
}
fa[now] = 0;//不被任何当作因子,即最后多棵树合并
dfs(now + 1);
}
int main()
{
cin>>n;
for(int i = 1;i <= n;i++)
{
cin>>a[i];
}
sort(a+1,a+1+n);
for(int i = 1;i <= n;i++)
ta[i] = a[i];
for(int i = 1;i <= n;i++)
{
llg tmp = a[i];
for(llg k = 2;k*k <= a[i];k++)
while(tmp%k == 0)
{
cnt[i]++;
tmp /= k;
}
if(tmp > 1) cnt[i]++;
}
dfs(1);
cout<<ans<<endl;
return 0;
}