NAIPC 2017 C, I

题目链接

C. Greetings!

dp[S][k]表示S集合使用k种信封的最小浪费。
先求出dp[S][1],然后枚举每种状态的子集,不断缩小浪费。

对于一个二进制状态S,它的所有子集可以由下面这个方式枚举:

int S,set;
set = S;
while(set)	{set = (set-1)&S;}
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
#define clr(s, x) memset(s, x, sizeof(s))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
inline int read(){int r=0;char c=getchar();while(c<'0'||c>'9') {c=getchar();}while(c>='0'&&c<='9') {r=r*10+c-'0';c=getchar();}return r;}
inline ll readll(){ll r=0;char c=getchar();while(c<'0'||c>'9') {c=getchar();}while(c>='0'&&c<='9') {r=r*10+c-'0';c=getchar();}return r;}
inline ll qpow(ll a,ll b,ll mod){ll res=1;while(b){if(b&1)res = (res*a)%mod;a=(a*a)%mod;b>>=1;}return res;}
inline ll gcd(ll a,ll b){while(b^=a^=b^=a%=b);return a;}
const double eps = 1e-8;
const ll LLINF = 0x3f3f3f3f3f3f3f3f;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
const int MAXN = 1e5;
const int MAXM = 1e5;

int w[17], h[17], q[17];
ll dp[1<<17][17];
int main(int argc, char const *argv[])
{
	ios::sync_with_stdio(false);
	clr(dp, 0x3f);
	int n, K;
	cin >> n >> K;
	for(int i=0; i<n; ++i)	cin >> w[i] >> h[i] >> q[i];
	dp[0][0] = 0;
	for(int i=0; i<(1<<n); ++i){
		int maxw = 0, maxh = 0;
		for(int j=0; j<n; ++j){
			if((i>>j)&1){
				maxw = max(maxw, w[j]);
				maxh = max(maxh, h[j]);
			}
		}
		// printf("%d %d\n", maxw,maxh);
		dp[i][1] = 0;
		for(int j=0; j<n; ++j){
			if((i>>j)&1){
				dp[i][1] += q[j]*(1LL*maxw*maxh-w[j]*h[j]);
			}
		}
	}
	for(int i=0; i<(1<<n); ++i){
		for(int j=i; j; j=(j-1)&i){
			for(int k=1; k<=K; ++k){
				dp[i][k] = min(dp[i][k], dp[i-j][k-1]+dp[j][1]);
			}
		}
	}
	ll ans = LLINF;
	for(int i=0; i<=K; ++i)	ans = min(ans, dp[(1<<n)-1][i]);
	cout << ans << endl;
	return 0;
}

I. Tourists:

求树上i,j两点之间的距离,其中i是j的因子。

我们可以先求出LCA(i,j),然后套这个公式:
d i s t [ i , j ] = ( d i s [ i ] + d i s [ j ] 2 d i s [ L C A ( i , j ) ] + 1 ) dist[i,j] = (dis[i]+dis[j]-2*dis[LCA(i,j)]+1)
dis[i]表示1到i的距离。
最后要减去n,以为i != j。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e5+233;
int pre[N][30],deep[N],n;
int vis[N];
vector<int > e[N];
void bfs(int x){
	queue<int > que;
	que.push(x);
	vis[x] = 1;
	deep[x] = 1;
	while(!que.empty()){
		x = que.front(); que.pop();
		// printf("x:%d ", x);
		// printf("deep[%d]:%d\n",x,deep[x] );
		int size = e[x].size();
		for(int i=0;i<size;++i){
			int u = e[x][i];
			if(!vis[u]){
				vis[u] = 1;
				que.push(u);
				pre[u][0] = x;
				deep[u] = deep[x] + 1;
			}
		}
	}
}
void getpre(){
	for(int j=1;(1<<j)<=n;j++){
        for(int i=1;i<=n;i++){
        	if(pre[i][j-1] != -1)
        		pre[i][j]=pre[pre[i][j-1]][j-1];
        }
    }
}
int lca(int a,int b)
{
    int i,j;
    if(deep[a]<deep[b])swap(a,b);
    for(i=0;(1<<i)<=deep[a];i++);
    i--;
    for(j=i;j>=0;j--)
        if(deep[a]-(1<<j)>=deep[b])
            a=pre[a][j];
    if(a==b)return a;
    for(j=i;j>=0;j--)
    {
        if(pre[a][j]!=-1&&pre[a][j]!=pre[b][j])
        {
            a=pre[a][j];
            b=pre[b][j];
        }
    }
    return pre[a][0];
}

int main(){
	scanf("%d", &n);
	int u, v;
	memset(pre, -1, sizeof pre);
	for(int i=1; i<n; ++i){
		scanf("%d %d", &u,&v);
		e[u].push_back(v);
		e[v].push_back(u);
	}
	bfs(1);
	// for(int i=1; i<=n; ++i)	printf("%d\n", deep[i]);
	getpre();
	// for(int i=1; i<=n; ++i)	printf("%d\n", pre[i][0]);
	ll ans = 0;
	for(int i=1; i<=n; ++i){
		for(int j=i; j<=n; j+=i){
			ans += (deep[i]+deep[j]-2*deep[lca(i,j)]+1);
		}
	}
	printf("%lld\n", ans-n);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41009682/article/details/82926274
I2C
今日推荐