【9.7校内测试】【二分+spfa】【最长上升子序列】【状压DP+贪心(?)】
刘汝佳蓝书上的题,标程做法是从终点倒着$spfa$,我是二分答案正着$spfa$判断可不可行。效果是一样的。
【注意】多组数据建边一定要清零啊QAQ!!!
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std; int S, T, p; struct Node {
int v, nex;
Node ( int v = , int nex = ) :
v ( v ), nex ( nex ) { }
} Edge[]; int h[], stot;
void add ( int u, int v ) {
Edge[++stot] = Node ( v, h[u] );
h[u] = stot;
} int vis[], dis[];
queue < int > q;
bool Spfa ( int mid ) {
memset ( vis, , sizeof ( vis ) );
memset ( dis, -0x3f3f3f3f, sizeof ( dis ) );
q.push ( S ); vis[S] = ; dis[S] = mid;
while ( !q.empty ( ) ) {
int u = q.front ( ); q.pop ( ); vis[u] = ;
for ( int i = h[u]; i; i = Edge[i].nex ) {
int v = Edge[i].v;
if ( v > && dis[v] < dis[u] - ) {
dis[v] = dis[u] - ;
if ( !vis[v] ) { vis[v] = ; q.push ( v ); }
} else if ( v <= && ( dis[v] < dis[u] - ( dis[u] + ) / ) ) {
dis[v] = dis[u] - ( dis[u] + ) / ;
if ( !vis[v] ) { vis[v] = ; q.push ( v ); }
}
}
}
return dis[T] >= p;
} bool Check ( int mid ) {
return Spfa ( mid );
} int erfen ( ) {
int l = p, r = , ans;
while ( l <= r ) {
int mid = ( l + r ) >> ;
if ( Check ( mid ) ) r = mid - , ans = mid;
else l = mid + ;
}
return ans;
} int main ( ) {
freopen ( "toll.in", "r", stdin );
freopen ( "toll.out", "w", stdout );
int ti = , n;
while ( scanf ( "%d", &n ) == ) {
if ( n == - ) break;
memset ( h, , sizeof ( h ) );
for ( int i = ; i <= n; i ++ ) {
char u, v;
scanf ( "\n%c %c", &u, &v );
add ( u - 'A', v - 'A' );
add ( v - 'A', u - 'A' );
}
char s, t;
scanf ( "%d %c %c", &p, &s, &t );
S = s - 'A'; T = t - 'A';
int ans = erfen ( );
printf ( "Case %d: %d\n", ++ti, ans );
}
}
第一眼看到“最大独立集”,想的完了完了,不会啊怎么办。五分钟后,woc这不就是最长上升子序列吗,好水啊...然后心想这道题班上可能会全a吧,t3要认真才行叻。
结果原来大家都没发现吗...
可以发现每个点到原序列它后面比它小的点都连有一条双向边,要使一个集合里面任意两点都没有连边,在原序列里面这个集合就一定是一个不下降序列。要求最大,那就是最大上升子序列叻...(因为$a[i]$保证不等所以上升就好了
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std; int a[], dp[]; int main ( ) {
freopen ( "sort.in", "r", stdin );
freopen ( "sort.out", "w", stdout );
int n;
scanf ( "%d", &n );
for ( int i = ; i <= n; i ++ ) scanf ( "%d", &a[i] );
memset ( dp, 0x3f3f3f3f, sizeof ( dp ) );
for ( int i = ; i <= n; i ++ ) {
int pos = lower_bound ( dp + , dp + + n, a[i] ) - dp;
dp[pos] = a[i];
}
for ( int i = n; i >= ; i -- )
if ( dp[i] < 0x3f3f3f3f ) { printf ( "%d", i ); break; }
return ;
}
数据明显是状压,可是发现一个状态要存好多东西存不下怎么办!那就多开几个数组呗...
分别储存每个状态红、绿、白钥匙有多少个,每次更新首先保证所有钥匙的和是最大的,其次保证白钥匙数量最多。
然而是很不严谨的...QAQ(但是数据水我们就不在意这些细节叻~
这样会把一些情况给筛掉,导致后面的情况不能进入。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std; int n;
int Red[(<<)+], Green[(<<)+], White[(<<)+];
int R[], G[], KR[], KG[], W[]; int main ( ) {
freopen ( "room.in", "r", stdin );
freopen ( "room.out", "w", stdout );
scanf ( "%d", &n );
for ( int i = ; i <= n; i ++ ) scanf ( "%d", &R[i] );
for ( int i = ; i <= n; i ++ ) scanf ( "%d", &G[i] );
for ( int i = ; i <= n; i ++ ) scanf ( "%d", &KR[i] );
for ( int i = ; i <= n; i ++ ) scanf ( "%d", &KG[i] );
for ( int i = ; i <= n; i ++ ) scanf ( "%d", &W[i] );
int k0, k1, k2;
scanf ( "%d%d%d", &k0, &k1, &k2 );
memset ( Red, -, sizeof ( Red ) );
memset ( Green, -, sizeof ( Green ) );
memset ( White, -, sizeof ( White ) );
Red[] = k0, Green[] = k1, White[] = k2;
for ( int i = ; i < ( << n ); i ++ ) {
for ( int j = ; j <= n; j ++ ) {
if ( ! ( ( i >> ( j - ) ) & ) ) {
int s = i | ( << ( j - ) );
int wu = max ( G[j] - Green[i], );
if ( wu > White[i] ) continue;
if ( Red[i] + ( White[i] - wu ) >= R[j] ) {
int pre = Red[i] + Green[i] + White[i] - R[j] - G[j] + KR[j] + KG[j] + W[j];
int now = Red[s] + Green[s] + White[s];
if ( now <= pre ) {
int rn = max ( , R[j] - Red[i] ), gn = max ( , G[j] - Green[i] );
int wn = rn + gn;
if ( now == pre && White[s] > White[i] - wn + W[j] ) continue;
Red[s] = max ( , Red[i] - R[j] ) + KR[j], Green[s] = max ( , Green[i] - G[j] ) + KG[j] ;
White[s] = White[i] - wn + W[j];
}
}
}
}
}
int ans = ;
for ( int i = ; i < ( << n ); i ++ )
ans = max ( ans, Red[i] + Green[i] + White[i] );
printf ( "%d", ans );
return ;
}
正解如下:
#include<cstring>
#include<cstdio>
#include<iostream>
#define fo(i,n) for(int i=0;i<n;i++)
using namespace std;
const int N=;
int dR[N],dG[N],rR[N],rG[N],rW[N],ky[N],n,f[][],z;
int main(){
freopen("room.in","r",stdin);
freopen("room.out","w",stdout);
cin>>n;
fo(i,n) cin>>dR[i];
fo(i,n) cin>>dG[i];
fo(i,n) cin>>rR[i];
fo(i,n) cin>>rG[i];
fo(i,n) cin>>rW[i];
cin>>ky[]>>ky[]>>ky[];
int sum=ky[]+ky[]+ky[];
memset(f,-,sizeof f);
f[][ky[]]=ky[];
fo(i,<<n){
int k0=ky[],k1=ky[],r=sum;
fo(j,n)
if(i>>j&){
k0+=rR[j];
r+=rR[j]+rG[j]+rW[j]-dR[j]-dG[j];
}
for(int j=;j<=k0;j++){
if(f[i][j]==-) continue;
int fr=f[i][j];
int k=r-fr-j;
fo(l,n){
if(i>>l&) continue;
int r=max(,dR[l]-j),g=max(,dG[l]-k);
int &q=f[i|(<<l)][max(,j-dR[l])+rR[l]];
if(fr>=r+g)
q=max(q,fr-r-g+rW[l]);
}
z=max(z,j+k+fr);
}
}
cout<<z<<endl;
}
离$AK$只有清零一步之遥5555555,我还是tclQAQ
抱恨离场QAQ
【9.7校内测试】【二分+spfa】【最长上升子序列】【状压DP+贪心(?)】的更多相关文章
- 【bzoj5161】最长上升子序列 状压dp+打表
题目描述 现在有一个长度为n的随机排列,求它的最长上升子序列长度的期望. 为了避免精度误差,你只需要输出答案模998244353的余数. 输入 输入只包含一个正整数n.N<=28 输出 输出只包 ...
- BZOJ.3591.最长上升子序列(状压DP)
BZOJ 题意:给出\(1\sim n\)的一个排列的一个最长上升子序列,求原排列可能的种类数. \(n\leq 15\). \(n\)很小,参照HDU 4352这道题,我们直接把求\(LIS\)时的 ...
- bzoj5161 最长上升子序列 状压DP(DP 套 DP) + 打表
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5161 题解 回顾一下以前用二分求 LIS 的方法:令 \(f[i]\) 表示长度为 \(i\) ...
- BZOJ 5161: 最长上升子序列 状压dp+查分
好神啊 ~ 打表程序: #include <cstdio> #include <cstring> #include <algorithm> #define N 14 ...
- Luogu 3402 最长公共子序列(二分,最长递增子序列)
Luogu 3402 最长公共子序列(二分,最长递增子序列) Description 经过长时间的摸索和练习,DJL终于学会了怎么求LCS.Johann感觉DJL孺子可教,就给他布置了一个课后作业: ...
- 51nod 1376 最长上升子序列的数量 | DP | vector怒刷存在感!
51nod 1376 最长上升子序列的数量 题解 我们设lis[i]为以位置i结尾的最长上升子序列长度,dp[i]为以位置i结尾的最长上升子序列数量. 显然,dp[i]要从前面的一些位置(设为位置j) ...
- HDU3247 Resource Archiver (AC自动机+spfa+状压DP)
Great! Your new software is almost finished! The only thing left to do is archiving all your n resou ...
- bzoj3380: [Usaco2004 Open]Cave Cows 1 洞穴里的牛之一(spfa+状压DP)
数据最多14个有宝藏的地方,所以可以想到用状压dp 可以先预处理出每个i到j的路径中最小权值的最大值dis[i][j] 本来想用Floyd写,无奈太弱调不出来..后来改用spfa 然后进行dp,这基本 ...
- 【BZOJ-1097】旅游景点atr SPFA + 状压DP
1097: [POI2007]旅游景点atr Time Limit: 30 Sec Memory Limit: 357 MBSubmit: 1531 Solved: 352[Submit][Sta ...
随机推荐
- Ubuntu 下 CodeBlocks 修改用户自定义颜色主题 及 更新CodeBlocks到最新版本
Code::Blocks默认的白色编辑器界面看久了眼睛很累, 所以想换成dark的主题, 眼睛会舒服些. 1. 安装好codeblocks后, 先运行一次, 关闭, 这时程序会提示你是否要保存defa ...
- TensorFlow下利用MNIST训练模型识别手写数字
本文将参考TensorFlow中文社区官方文档使用mnist数据集训练一个多层卷积神经网络(LeNet5网络),并利用所训练的模型识别自己手写数字. 训练MNIST数据集,并保存训练模型 # Pyth ...
- Thinkphp的SQL查询方式
一.普通查询方式 a.字符串$arr=$m->where("sex=0 and username='gege'")->find();b.数组$data['sex']=0 ...
- SSO单点登录的发展由来以及实现原理【转】
单点登录以及权限,在很早之前都有写过,不过都比较简单,今天就具体说一下,以及下一步要做的 1.web单系统应用 早期我们开发web应用都是所有的包放在一起打成一个war包放入tomcat容器来运行的, ...
- NEERC2014
NEERC2014 A - Alter Board 题目描述:给出一个\(n \times m\)的国际象棋棋盘,每次选定一个矩形,使得矩形中的每个格子的颜色翻转,求出最少次数的方案使得最终棋盘只有一 ...
- Minimum Palindromic Factorization(最少回文串分割)
Minimum Palindromic Factorization(最少回文串分割) 以下内容大部分(可以说除了关于回文树的部分)来自论文A Subquadratic Algorithm for Mi ...
- rpmdb: Thread/process 9180/139855524558592 failed: Thread died in Berkeley DB library
使用yum安装出现问题:rpmdb: Thread/process 9180/139855524558592 failed: Thread died in Berkeley DB library 解决 ...
- MongoDB 3.x 安装配置
目录 (见右侧目录栏导航)- 1. 安装Mongodb - 1.1 使用二进制包安装 - 1.2 运行MongoDB- 2. MongoDB 配置文件详解 - 2.1 说明 - ...
- hive(七)hive-运行方式、GUI接口、权限管理
1.Hive运行方式: 命令行方式cli:控制台模式 脚本运行方式(实际生产环境中用最多) JDBC方式:hiveserver2 web GUI接口 (hwi.hue等) 1.1Hive在CLI模 ...
- prototype 与 __proto__
原文:http://rockyuse.iteye.com/blog/1426510 说到prototype,就不得不先说下new的过程. 我们先看看这样一段代码: 1 <script type= ...