Gym101002 2016NAIPC(队内第7次训练)
(由于先看的最后一题,然后又一直WA,导致这场有点爆炸,我背锅。
A .Fancy Antiques
题意: 选择最多k个商店,买n个物品,每个物品分别对应两个店售卖,求最小花费是多少。n<100,k=m<=40;
思路:搜索。。。。开始以为是个费用流,然后没法限制。加N多减枝,然后....
B. 好像没什么可以学的,懒得看了
C .Greetings!
pro:N种卡片,用K种格子去装。问浪费的空间。N,K<15
sol:比较小,状态压缩。
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int n,k,w[],h[],q[];
long long f[<<][];
int main(){
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++)scanf("%d%d%d",w+i,h+i,q+i);
memset(f,,sizeof(f));
for(int i=;i<=k;i++)f[][i]=;
for(int i=;i<(<<n);i++)
for(int p=i;p;p=(p-)&i){
int maxw=,maxh=;long long now=;
for(int j=;j<=n;j++)
if(<<(j-)&p)maxw=max(maxw,w[j]),maxh=max(maxh,h[j]);
for(int j=;j<=n;j++)
if(<<(j-)&p)now+=(long long)(maxw*maxh-w[j]*h[j])*q[j];
for(int j=;j<=k;j++)
f[i][j]=min(f[i][j],f[i^p][j-]+now);
}
printf("%lld",f[(<<n)-][k]);
return ;
}
D .Programming Team
题意:给定一棵大小为N的点权树(si,pi),现在让你选敲好K个点,需要满足如果如果u被选了,那么fa[u]一定被选,现在要求他们的平均值(pi之和/si之和)最大。
思路:均值最大,显然需要01分数规划,但是后面怎么高效的做背包,我是不会的,我只会暴力的背包,O(N*K*K)。 还好队友会,叫“树上依赖背包”,即要问树转化为DFS序,按照倒序来DP,复杂度O(N*K)。dp[i][j]=max(dp[i+1][j-v[x]]+w[x],dp[i+sz[x]][j]),分别对应x选或者不选(其中x是DFS序为i的点)。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=;
const double inf=1e20;
double dp[maxn][maxn],s[maxn],p[maxn],val[maxn];
int r[maxn],Laxt[maxn],Next[maxn],To[maxn];
int pos[maxn],tot,cnt,N,K,sz[maxn];
void add(int u,int v)
{
Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v;
}
void dfs(int u)
{
sz[u]=; tot++; pos[tot]=u;
for(int i=Laxt[u];i;i=Next[i]){
dfs(To[i]); sz[u]+=sz[To[i]];
}
}
bool check(double Mid)
{
rep(i,,N) val[i]=p[i]-s[i]*Mid;
rep(i,,tot+) rep(j,,K) dp[i][j]=-inf;
rep(i,,tot+) dp[i][]=;
for(int i=tot;i>=;i--){
int x=pos[i];
for(int j=;j<=K;j++){
dp[i][j]=max(dp[i+][j-]+val[x],dp[i+sz[x]][j]);
}
}
return dp[][K]>=;
}
int main()
{
scanf("%d%d",&K,&N); K++;
rep(i,,N){
scanf("%lf%lf%d",&s[i],&p[i],&r[i]);
add(r[i],i);
}
dfs();
double L=,R=,Mid,ans=; int T=;
while(T--){
Mid=(L+R)/;
if(check(Mid)) ans=max(Mid,ans),L=Mid;
else R=Mid;
}
printf("%.3lf\n",ans);
return ;
}
E. K-Inversions
pro:对(A,B)的长度贡献。
sol:FFT模板题。
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
struct cp{
double x,y;
cp operator +(const cp&a)const{
return (cp){x+a.x,y+a.y};
}
cp operator -(const cp&a)const{
return (cp){x-a.x,y-a.y};
}
cp operator *(const cp&a)const{
return (cp){x*a.x-y*a.y,x*a.y+y*a.x};
}
}a[],b[],c[];
int n,m,len,ans[];char s[];
double pi=3.14159265358979323846;
void DFT(cp *a,int len,int type){
for(int i=,t=;i<len;i++){
if(i<t)std::swap(a[i],a[t]);
for(int j=len>>;(t^=j)<j;j>>=);
}
for(int h=;h<=len;h<<=){
cp wn=(cp){cos(pi**type/h),sin(pi**type/h)};
for(int i=;i<len;i+=h){
cp w=(cp){,},t;
for(int j=;j<h>>;j++,w=w*wn){
t=a[i+j+(h>>)]*w;
a[i+j+(h>>)]=a[i+j]-t;
a[i+j]=a[i+j]+t;
}
}
}
}
int main(){
scanf("%s",s);n=strlen(s);
for(int i=;i<n;i++)
if(s[i]=='A')a[i].x=;
else b[n-i-].x=;
for(len=;len<=n+n;len<<=);
DFT(a,len,),DFT(b,len,);
for(int i=;i<len;i++)c[i]=a[i]*b[i];
DFT(c,len,-);
for(int i=;i<len;i++)ans[i]=c[i].x/len+0.1;
for(int i=n;i<n+n-;i++)printf("%d\n",ans[i]);
return ;
}
G .Symmetry
pro:现在给你二维平面上N个点,现在让你求,加最少的点,使得所有点关于同一个点或者线有对称点。N<1e3;
sol:好像是枚举的,枚举对称中心,枚举对称轴,复杂度O(N^3);
H .Jewel Thief
pro:给定N,M。输入N个物品,(si,vi)表示第i个物品体积为si,价值为vi,s<=300,vi<=1e9; N<1e6;现在要求,对于背包体积为1到M时,求出最大背包价值。
sol:显然直接跑背包会爆炸。 发现物品体积都比较小,我们先对相同体积的排序,对于体积相同的一起处理。
然后发现转移都是在差为体积整数倍之间,按照容量对体积取模分组 ,发现组内部转移满足神奇的决策单调性。 然后就是s次分治。
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define rep2(i,a,b) for(int i=b;i>=a;i--)
using namespace std;
const int maxn=;
const int maxm=;
ll dp[][maxm];
vector<ll>G[maxn]; int x,d,t;
void get(int L,int R,int l,int r)
{
if(L>R) return ;
int Mid=(L+R)>>,pos=Mid;
for(int i=min(r,Mid-);i>=l;i--){
if(Mid-i>G[x].size()) break;
if(dp[t][d+Mid*x]<dp[t^][d+i*x]+G[x][Mid-i-]){
pos=i; dp[t][d+Mid*x]=dp[t^][d+i*x]+G[x][Mid-i-];
}
}
get(L,Mid-,l,pos);
get(Mid+,R,pos,r);
}
int main()
{
int N,M,s;ll v;
scanf("%d%d",&N,&M);
rep(i,,N){
scanf("%d%lld",&s,&v);
G[s].push_back(v);
}
rep(i,,){
if(G[i].size()==) continue;
sort(G[i].begin(),G[i].end(),greater<int>() );
for(int j=;j<G[i].size();j++) G[i][j]+=G[i][j-];
t^=; rep(j,,M) dp[t][j]=dp[t^][j];
rep(j,,i-){
d=j; x=i;
get(,(M-j)/i,,(M-j)/i);
}
rep(j,,M) dp[t][j]=max(dp[t][j],dp[t][j-]);
}
rep(i,,M) printf("%lld ",dp[t][i]);
return ;
}
I. Tourists
pro:给定一棵树,求所有倍数关系的点之间距离之和。
sol:枚举所有的,倍增求LCA,O(N*logN*logN),也可以用ST表O(NlogN);
#include<bits/stdc++.h>
#define pii pair<int,int>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
struct edge{
int d,nex;
}e[];
int n,q[],l,efree,d[],f[][];
long long ans;
inline void add(int x,int y){e[++efree]=(edge){y,q[x]};q[x]=efree;}
void dfs(int x,int y){
f[][x]=y;d[x]=d[y]+;
for(int i=q[x];i;i=e[i].nex)
if(e[i].d!=y)dfs(e[i].d,x);
}
inline int lca(int x,int y){
if(d[x]>d[y])swap(x,y);
for(int i=log2(d[y]-d[x]);i>=;i--)
if(d[f[i][y]]>=d[x])y=f[i][y];
if(x==y)return x;
for(int i=log2(d[x]);i>=;i--)
if(f[i][x]!=f[i][y])x=f[i][x],y=f[i][y];
return f[][x];
}
int main(){
scanf("%d",&n);
for(int i=;i<n;i++){
int x,y;scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
dfs(,);l=log2(n);
for(int i=;i<=l;i++)
for(int j=;j<=n;j++)f[i][j]=f[i-][f[i-][j]];
for(int i=;i<=n>>;i++)
for(int j=i+i;j<=n;j+=i){
int fa=lca(i,j);
ans+=d[i]+d[j]-*d[fa]+;
}
printf("%lld",ans);
return ;
}
F. Mountain Scenes
pro:给定总长度为N的木棍,一个W*H的框框,问有多少种分放方式,使得图案不是平的。N<10000;W,H<100
sol:DP即可,用总的分放方案减去平的。
#include<bits/stdc++.h>
#define pii pair<int,int>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
ll dp[][];
const int MOD = 1e9 + ;
int main()
{
int n, w, h;
scanf("%d%d%d", &n, &w, &h);
if(n > w * h)n = w * h;
for(int i = ; i <= w; i++)dp[i][] = ;
for(int i = ; i <= w; i++)
for(int j = ; j <= n && j <= i * h; j++)
for(int k = ; k <= h && k <= j; k++)dp[i][j] += dp[i - ][j - k], dp[i][j] %= MOD;
ll ans = ;
for(int i = ; i <= n; i++)ans += dp[w][i], ans %= MOD;
ans -= (n / w);
printf("%lld\n", ans);
return ;
}
J .Whiteboard
pro:给定N*M的画板,然后给定画板的最终状态,以及画笔的走向。现在在某个时间T,画笔变为了橡皮擦,即最开始画板的白色的,T之前笔走过是染黑,T之后笔走过的漂白,求T的范围[L,R],不存在则输出-1 -1。
sol:首先,如果画笔没有走过的地方是黑色'#',则无解。
对于画笔走过的地方,我们关系的其实只有最后一次走过的时间ti,对于黑色,L>=ti; 对于白色,R<ti;
这种题,我们倒着去删点就可以了,删点可以利用并查集,链表,或者直接用set的二分功能即可。
注意使用long long。
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=;
char c[maxn],s[maxn],q[maxn][];
set<int>RR[maxn],CC[maxn];
set<int>::iterator it;
int d[maxn],X[maxn],Y[maxn],N,M,Q;
ll times[maxn],Mx[maxn];
void solve(int nowx,int nowy,int tox,int toy,int x,int y,ll nowt)
{
if(abs(x)==){
int L=min(nowx,tox),R=max(nowx,tox);
for(it=CC[nowy].lower_bound(L);;it=CC[nowy].lower_bound(L)){
if(it==CC[nowy].end()||(*it)>R) break;
L=*it;CC[nowy].erase(it);
RR[L].erase(RR[L].find(nowy));
Mx[(L-)*M+nowy]=nowt+abs(L-nowx);
}
}
else {
int L=min(nowy,toy),R=max(nowy,toy);
for(it=RR[nowx].lower_bound(L);;it=RR[nowx].lower_bound(L)){
if(it==RR[nowx].end()||(*it)>R) break;
L=*it;RR[nowx].erase(it);
CC[L].erase(CC[L].find(nowx));
Mx[(nowx-)*M+L]=nowt+abs(L-nowy);
}
}
}
int main()
{
scanf("%d%d%d",&N,&M,&Q);
for(int i=N;i>=;i--) {
scanf("%s",c+);
rep(j,,M) s[(i-)*M+j]=c[j];
}
rep(i,,Q) scanf("%s%d",q[i],&d[i]);
rep(i,,N)
rep(j,,M) RR[i].insert(j),CC[j].insert(i);
X[]=; Y[]=; times[]=;
rep(i,,Q){
if(q[i][]=='u') X[i]=X[i-]+d[i],Y[i]=Y[i-];
else if(q[i][]=='d') X[i]=X[i-]-d[i],Y[i]=Y[i-];
else if(q[i][]=='r') X[i]=X[i-],Y[i]=Y[i-]+d[i];
else X[i]=X[i-],Y[i]=Y[i-]-d[i];
times[i]=times[i-]+d[i];
}
for(int i=Q;i>=;i--){
if(q[i][]=='u') solve(X[i-],Y[i-],X[i],Y[i],,,times[i-]);
else if(q[i][]=='d') solve(X[i-],Y[i-],X[i],Y[i],-,,times[i-]);
else if(q[i][]=='l') solve(X[i-],Y[i-],X[i],Y[i],,-,times[i-]);
else solve(X[i-],Y[i-],X[i],Y[i],,,times[i-]);
}
ll L=,R=times[Q];
rep(i,,N*M){
if(!Mx[i]&&s[i]=='#') R=-;
if(!Mx[i]) continue;
if(s[i]=='#') L=max(L,Mx[i]);
else R=min(R,Mx[i]-);
}
if(L<=R) printf("%lld %lld\n",L,R);
else puts("-1 -1");
return ;
}
K .YATP
题意:给定带点权边权的树,定义路径的花费=路径边权和e+起点点权w[s]*终点点权w[t]。N<2e5,e,w<1e6;
思路:首先,需要树分治。 然后得到方程dp[i]=min{ dis[i]+dis[j]+w[i]*w[j] },很显然需要斜率优化。
注意维护凸包的时候是需要保证w[j]是单调的,这样才能用不等式维护队尾。 由于w[i]不是对应的队尾,所以我们还要二分凸包。
还有个问题,怎么确定我们得到的i和j不是在同一个子树呢? 因为如果在一颗子树的时候dp[i]=dis[i]+dis[j]+w[i]*w[j]-2*dis[LCA]。 其实没必要考虑这个问题,因为当LCA为根的时候会更新答案。(这一点想不到估计要很难去维护了)
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=;
int Laxt[maxn],Next[maxn],To[maxn],Len[maxn],cnt;
int sz[maxn],son[maxn],rt,all,vis[maxn],S[maxn],tot;
ll ans[maxn],a[maxn],dis[maxn],sum; int q[maxn],top;
bool cmp(int x,int y)
{
int xx=x,yy=y;
if(a[xx]==a[yy]) return dis[xx]<dis[yy];
return a[xx]<a[yy];
}
ll getans(int p,int k)
{
return dis[k]+dis[p]+a[p]*a[k];
}
void add(int u,int v,int w)
{
Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; Len[cnt]=w;
}
void dfs1(int u,int f)
{
sz[u]=; son[u]=;
for(int i=Laxt[u];i;i=Next[i]){
if(To[i]!=f&&!vis[To[i]]) {
dfs1(To[i],u);
sz[u]+=sz[To[i]];
son[u]=max(son[u],sz[To[i]]);
}
}
son[u]=max(son[u],all-son[u]);
if(son[u]<son[rt]) rt=u;
}
void cal(int p)
{
if(top==) return ;int L=,R=top-,Mid;
ans[p]=min(ans[p],getans(p,q[top]));
while(L<=R){
Mid=(L+R)>>;
ll tmp1=getans(p,q[Mid]),tmp2=getans(p,q[Mid+]);
if(tmp1<tmp2) R=Mid-,ans[p]=min(ans[p],tmp1);
else L=Mid+,ans[p]=min(ans[p],tmp2);
}
}
void get(int u,int f)
{
cal(u);
for(int i=Laxt[u];i;i=Next[i])
if(To[i]!=f&&!vis[To[i]]) get(To[i],u);
}
bool check(int p){
return (dis[p]-dis[q[top]])*(a[p]-a[q[top-]])<=
(dis[p]-dis[q[top-]])*(a[p]-a[q[top]]);
}
void ADD(int p)
{
if(top&&a[p]==a[q[top]]&&dis[p]<dis[q[top]]) top--;
while(top>&&check(p)) top--;
q[++top]=p;
}
void get(int u,int f,ll D)
{
dis[u]=D; sz[u]=; S[++tot]=u;
for(int i=Laxt[u];i;i=Next[i])
if(To[i]!=f&&!vis[To[i]]){
get(To[i],u,D+Len[i]);
sz[u]+=sz[To[i]];
}
}
void solve(int u,int f)
{
vis[u]=; dis[u]=;
top=; tot=; S[++tot]=u;
for(int i=Laxt[u];i;i=Next[i]){
if(!vis[To[i]]&&To[i]!=f)
get(To[i],u,Len[i]);
}
sort(S+,S+tot+,cmp);
rep(i,,tot) ADD(S[i]);
rep(i,,tot) cal(S[i]);
for(int i=Laxt[u];i;i=Next[i]){
int v=To[i];
if(!vis[v]&&v!=f) {
all=sz[v]; rt=;
dfs1(v,); solve(rt,);
}
}
}
int main()
{
int N,u,v,w;
scanf("%d",&N); son[]=N+;
rep(i,,N) scanf("%lld",&a[i]);
rep(i,,N) ans[i]=a[i]*a[i];
rep(i,,N-){
scanf("%d%d%d",&u,&v,&w);
add(u,v,w); add(v,u,w);
}
all=N; rt=;
dfs1(,); solve(rt,);
rep(i,,N) sum+=ans[i];
printf("%lld\n",sum);
return ;
}
Gym101002 2016NAIPC(队内第7次训练)的更多相关文章
- Gym - 101480 CERC 15:部分题目题解(队内第N次训练)
-------------------题目难度较难,但挺有营养的.慢慢补. A .ASCII Addition pro:用一定的形式表示1到9,让你计算加法. sol:模拟. solved by fz ...
- Gym101485: NWERC 2015(队内第6次训练)
A .Assigning Workstations 题意:给定N个人的工作时间和工作时长,我们可以假设有无数台工作机器,如果一台机器超过M时间未使用就会关闭,那么我们怎么安排机器的使用,使得需要开启机 ...
- Gym101482 NWERC 2014(队内训练第4场)
-----------------------前面的两场感觉质量不高,就没写题解----------------------------- A .Around the Track pro:给定内多边形 ...
- OI队内测试一【数论概率期望】
版权声明:未经本人允许,擅自转载,一旦发现将严肃处理,情节严重者,将追究法律责任! 序:代码部分待更[因为在家写博客,代码保存在机房] 测试分数:110 本应分数:160 改完分数:200 T1: 题 ...
- OI队内测试——石门一
T1: 题目大意: 给你一个立方体,每个面上有些数字,给你一个数字K,你可以玩K轮游戏, 每轮你会将每个面上的数均分为4份,分给相邻的面,求K轮游戏后,上面的数字是 依次给你前.后.上.下.左.右的起 ...
- OI队内测试二【数论概率期望】
版权声明:未经本人允许,擅自转载,一旦发现将严肃处理,情节严重者,将追究法律责任! 序:代码部分待更[因为在家写博客,代码保存在机房] T1: 题解:插头dp应该很好想吧,我们考虑当出现转折时我们对下 ...
- 0513JS数组遍历、内置方法、训练
一.定义一个数组把其中的偶数取出,组成一个新的数组 var attr = [9,34,80,27,56]; var attr1 = []; for(var i in attr){ if(attr[i] ...
- NOIP队内凉心互测总结(8.22update)
8.22(结束后一天) __stdcall讲题qwq 全是CF原题 D1T1 一看像是结论题,打了下表,水过 没错就是结论题,直接暴力就好 D1T2 看起来不好做,没有AC思路 打了暴力 40分 T2 ...
- 【zznu-夏季队内积分赛3-J】追忆
题目描述 “别人总说我瓜,其实我一点也不瓜,大多数时候我都机智的一批“现在是阳历2018/8/7,宝儿姐想起自己参加ACM整整1000天了.她想知道她刚入坑是什么时间.那么问题来了,请帮宝儿姐追忆一下 ...
随机推荐
- maven plugins
<build> <finalName>lessons</finalName> <plugins> <plugin> <groupId& ...
- MySQL(一) 初识MySQL
数据库基础 数据库是由一批数据构成的有序的集合,这些数据被存放在结构化的数据表里.数据表之间相互联系,反映了客观事物间的本质联系.数据库系统提供对数据的安全控制和完整性控制. 什么是数据库 数据库的发 ...
- learning scala 数组和容器
数组:可变的,可索引的,元素具有相同类型的数据集合 一维数组 scala> val intValueArr = new Array[Int](3)intValueArr: Array[Int] ...
- java 的类型转换方式
隐式转换 byte等整型转int,最高位(符号位保留),中间补0 byte bt=-13; bt 源码:1000 1101 反码:1111 0010 补码:1111 0011 int it=bt; i ...
- MySQL字符集与校对
一.什么是字符集与校对 1.字符集与校对 字符集是指一种从二进制编码到某种字符符号的映射. 校队是指一组用于某个字符集的配许规则. 2.utf8与utf8mb4 标准的UTF-8字符集编码是可以使用1 ...
- caffe,Inception v2 Check failed: top_shape[j] == bottom[i]->shape(j)
使用Caffe 跑 Google 的Inception V2 对输入图片的shape有要求,某些shape输进去可能会报错. Inception model中有从conv和pooling层concat ...
- Java:将数据库数据导出到Excel (一眼就看会)
所用Jar包 1. sqljdbc4.jar 连接数据库的Jar包(根据数据库的不同进行选择,我用的SqlServer2008) 2.Jxl.jar 访问Excel的Jar包 注意:支持以.xls结尾 ...
- 读书笔记 C# 接口之浅析
一.接口可以包含 属性.方法.事件和索引器: 二.接口不能被实例化: 三.一个类可以继承多个接口: 四.接口不能包含方法的实现: 五.继承接口的类必须实现接口中所有成员: 六.显式实现接口的成员,不能 ...
- Java进程和线程
进程是资源分配和任务调度的基本单位, 进程就是包含上下文切换的程序执行时间总和=CPU加载上下文环境+CPU执行+CPU保存上下文环境,可以理解为时间片段: 进程的颗粒度太大了,将进程分块,按照a,c ...
- Oracle中sysdba身份和dba角色区别
sysdba身份登陆可以打开,关闭数据库,创建SPFILE,对数据库进行恢复操作等,而这些是DBA角色无法实现的:sysdba 是系统权限,dba是用户对象权限: sysdba,是管理oracle实例 ...