2019 HZNU Winter Training Day 15 Comprehensive Training
A - True Liars
题意:
那么如果一个人说另一个人是好人,那么如果这个人是好人,说明 对方确实是好人,如果这个是坏人,说明这句话是假的,对方也是坏人。
如果一个人说另一个人是坏人,那么如果这个人是好人,说明对方是坏人,如果这个是坏人,说明 对方是好人。
也就是如果条件是yes说明这两个是相同集合的,否则是两个不同的集合。
思路:
用r[i]表示i结点与根结点的关系,0为相同集合,1为不同集合。这是一个经典的并查集问题。
这样处理之后,还需要判断是否唯一
我们通过并查集,可以将所有人分为若干个集合,其中对于每一个集合,又分为两个集合(好人和坏人,但是不知道哪些是好人,哪些是坏人,我们只有相对关系)
接下来就是从所有大集合中的两个小集合取一个,组成好人集合,判断是否唯一。
背包问题,dp[i][j]表示前i个大集合,好人为j个的方案有多少种,或者dp[i][j]表示当前好人i个,坏人j个的情况有多少种
如果dp[cnt][p1]!=1说明方案不唯一,或者无解。
输出方案就是加个pre数组,从后往前递推呢。
代码:
/*
POJ 1417
*/
#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
#include <vector>
#include <string>
using namespace std; const int MAXN=;
int F[MAXN];
int val[MAXN];
int find(int x)
{
if(F[x]==-)return x;
int tmp=find(F[x]);
val[x]+=val[F[x]];
val[x]%=;
return F[x]=tmp;
}
int a[MAXN][];//a[i][0],a[i][1]表示每个大集合分成两部分的个数
vector<int>b[MAXN][];
bool used[MAXN];
int dp[MAXN][MAXN/];
int pre[MAXN][MAXN/];
int main()
{
int n,p1,p2;
while(scanf("%d%d%d",&n,&p1,&p2)==)
{
if(n== && p1== && p2==)break;
memset(F,-,sizeof(F));
memset(val,,sizeof(val));
int u,v;
char str[];
while(n--)
{
scanf("%d%d%s",&u,&v,&str);
int tmp;
if(str[]=='y')//相同
tmp=;
else tmp=;//相反
int t1=find(u),t2=find(v);
if(t1!=t2)
{
F[t1]=t2;
val[t1]=(val[v]-val[u]+tmp+)%;
}
}
for(int i=;i<MAXN;i++)
{
b[i][].clear();
b[i][].clear();
a[i][]=;
a[i][]=;
}
memset(used,false,sizeof(used));
int cnt=;
for(int i=;i<=p1+p2;i++)
if(!used[i])
{
int tmp=find(i);
for(int j=i;j<=p1+p2;j++)
{
if(find(j)==tmp)
{
used[j]=true;
b[cnt][val[j]].push_back(j);
a[cnt][val[j]]++;
}
}
cnt++;
}
memset(dp,,sizeof(dp));
dp[][]=;
for(int i=;i<cnt;i++)
{
for(int j=p1;j>=;j--)
{
if(j-a[i][]>= && dp[i-][j-a[i][]])
{
dp[i][j]+=dp[i-][j-a[i][]];
pre[i][j]=j-a[i][];
} if(j-a[i][]>= && dp[i-][j-a[i][]])
{
dp[i][j]+=dp[i-][j-a[i][]];
pre[i][j]=j-a[i][];
} }
}
if(dp[cnt-][p1]!=)
{
printf("no\n");
}
else
{
vector<int>ans;
ans.clear();
int t=p1;
//printf("%d\n",cnt); for(int i=cnt-;i>=;i--)
{
int tmp=t-pre[i][t];
//printf("%d\n",i);
//printf("%d %d\n",t,tmp);
if(tmp==a[i][])
{
for(int j=;j<a[i][];j++)
ans.push_back(b[i][][j]);
}
else
{
for(int j=;j<a[i][];j++)
ans.push_back(b[i][][j]);
}
t=pre[i][t];
} sort(ans.begin(),ans.end());
for(int i=;i<ans.size();i++)
printf("%d\n",ans[i]);
printf("end\n");
} }
return ;
}
B - The Shortest Path in Nya Graph
题意:有n个点 , m条无向边 ,每条边都是有权值, 并且每个点属于一个楼层 ,楼层上的点到可以到相邻楼层的任意一点 ,但是要花费 c 。没有点的相邻楼层不能互达。求 1 到 n的最小花费。
思路:图建好了就是裸的最短路了。但是建图有点麻烦,参考了别人的代码之后才明白为什么要这样建图。
把楼层看成一个点,第i层可以看成第n+i个点。楼层与该楼层上的点建边,边权为0,单向;楼层与
相邻楼层建边,边权为C,双向;相邻楼层上的点与该楼层建边,边权为C,单向。
代码:
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#define N 200100
#define ll long long using namespace std;
const int inf=0x3f3f3f3f;
int n,m,c;
int lay[N];
bool hava[N]; bool vis[N];
int cnt[N];
int dist[N];
struct Edge {
int v;
int cost;
Edge(int _v=,int _c=):v(_v),cost(_c) {}
bool operator <(const Edge &r)const {
return cost>r.cost;
}
};
vector<Edge>E[N];
void addedge(int u,int v,int w) {
Edge it;
it.v=v;
it.cost=w;
E[u].push_back(it);
} void Dijk(int n,int start) { //点的编号从1开始
memset(vis,false,sizeof(vis));
for(int i=; i<=n*; i++)dist[i]=inf;
priority_queue<Edge>que;
while(!que.empty())que.pop();
dist[start]=;
que.push(Edge(start,));
Edge tmp;
while(!que.empty()) {
tmp=que.top();
que.pop();
int u=tmp.v;
if(vis[u])continue;
vis[u]=true;
for(int i=; i<E[u].size(); i++) {
int v=E[tmp.v][i].v;
int cost=E[u][i].cost;
if(!vis[v]&&dist[v]>dist[u]+cost) {
dist[v]=dist[u]+cost;
que.push(Edge(v,dist[v]));
} }
}
} int main() {
// freopen("test.in","r",stdin);
int t;
cin>>t;
int ca=;
while(t--) {
for(int i=; i<=n*+; i++)E[i].clear();
scanf("%d%d%d",&n,&m,&c);
memset(hava,,sizeof hava);
for(int i=; i<=n; i++) {
scanf("%d",&lay[i]);
hava[lay[i]]=true;
}
int u,v,cost;
for(int i=; i<=m; i++) {
scanf("%d%d%d",&u,&v,&cost);
addedge(u,v,cost);
addedge(v,u,cost);
}
if(n<=) {
printf("Case #%d: 0\n",ca++);
continue;
} for(int i=; i<n; i++) {
if(hava[i]&&hava[i+]) {
addedge(n+i,n+i+,c);
addedge(n++i,n+i,c);
}
}
for(int i=; i<=n; i++) {
addedge(lay[i]+n,i,);
if(lay[i]>)addedge(i,lay[i]-+n,c);
if(lay[i]<n)addedge(i,lay[i]++n,c);
}
Dijk(n,);
printf("Case #%d: %d\n",ca++,dist[n]>=inf?-:dist[n]);
}
return ;
}
C - The Super Powers
题意:给你一个关于超级幂数的定义,只要一个数是至少两个数的幂,即为超级幂数。例如64=8*8=4*4*4。输出1~2^64-1内所有的超级幂数。
思路:一开始的思想暴力,但是肯定很慢。有两个比较重要的思路:① 找num^x<2^64-1的时候,尝试两边取对数,然后确定x<ln(2^64-1)/ln(num),x在4~ln(2^64-1)/ln(num)里取。② 只有合数的时候才能产生超级幂数,然后判断是否为素数即可。
还有很重要的一点,pow会出错。谨慎使用,wa了很多次,用快速幂才ac。
扔进set里遍历输出即可。
代码:
/*
I have a dream!A AC deram!!
orz orz orz orz orz orz orz orz orz orz orz
orz orz orz orz orz orz orz orz orz orz orz
orz orz orz orz orz orz orz orz orz orz orz */ #include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<stack>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e4 + ;
const int N = ;
#define pa pair<int,int>
inline int read()
{
int x = , f = ; char ch = getchar(); for (; !isdigit(ch); ch = getchar())if (ch == '-')f = -;
for (; isdigit(ch); ch = getchar())x = x * + ch - ''; return x * f;
} bool isPrime(int n)
{
if (n <= )
return n > ;
else if (n % == || n % == )
return false;
else
{
for (int i = ; i * i <= n; i += )
if (n % i == || n % (i + ) == )
return false;
}
return true;
} ull qsm(int a, int b)
{
ull ans = , base = a;
while (b != ) {
if (b & != ) {
ans *= base;
}
base *= base;
b >>= ;
}
return ans;
} int main()
{
set<ull>ans;
ans.insert();
ull maxx = ;
for (int num = ; num < 1e5; num++)
{
if (pow(num, ) > maxx) break;
double m = log(maxx) / log(num);
for (int i = ; i < m; i++)
{
if (isPrime(i)) continue;
ull p = qsm(num, i);
ans.insert(p);
}
} set<ull>::iterator it;
//int cnt = 0;
for (it = ans.begin(); it != ans.end(); it++)
{
//cnt++;
//if (cnt == 10) break;
printf("%llu\n", *it);
}
return ;
}
D - Music Festival
题意:给你n组区间,每个居间都带有权值,让你选取一些区间使得区间不想交并且权值最大(要每组都至少有一个区间被选到)。
思路:n最多十组,我们就可以用二进制来记录当前唱歌的状态,然后离散化区间点(这样我们就可以用连续的点去表示这些区间),这样就有dp【i】【j】,i表示当前的区间点,j表示当前的状态,dp【i1】【j1】=dp【i】【j】+num【k】。每次寻找当前点往右 能更新的最近的一个区间(一切切的一切都是膜拜大佬的博客来的,离散化真是个好东西)
---------------------
作者:liexss
来源:CSDN
原文:https://blog.csdn.net/liexss/article/details/83511980
代码:
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<map>
#include<iostream>
using namespace std;
struct inst {
int x, y;
int sud;
int id;
};
inst ax[];
int dp[][];
int bn[];
int maxn[];
int tot, cnt;
map<int, int>q;
int cmp(inst a, inst b) {
if (a.x!=b.x)return a.x < b.x;
else return a.y < b.y;
}
int binary_s(int x) {
int l = ;
int r = tot-;
int ans = tot-;
while (l <= r) {
int mid = (l + r) / ;
if (ax[mid].x >= x) {
ans = mid;
r = mid - ;
}
else l = mid + ;
}
if (x > ax[ans].x) ans++;
return ans;
}
int main(void) {
int n;
scanf("%d", &n);
tot = ;
cnt = ;
q.clear();
memset(maxn, 0x8f, sizeof(maxn));
memset(dp, 0x8f, sizeof(dp));
for (int i = ; i <= n; i++) {
int m;
scanf("%d", &m);
for (int z = ; z < m; z++) {
scanf("%d %d %d", &ax[tot].x, &ax[tot].y,&ax[tot].sud);
ax[tot].id = i-;
bn[cnt++] = ax[tot].x;
bn[cnt++] = ax[tot].y;
tot++;
}
}
sort(bn, bn + cnt);
cnt = unique(bn,bn + cnt) - bn;
sort(ax, ax + tot, cmp);
for (int i = ; i < cnt; i++) {
q[bn[i]] = i;
}
for (int i = ; i < tot; i++) {
ax[i].x = q[ax[i].x];
ax[i].y = q[ax[i].y];
}
dp[][] = maxn[] = ;
for (int i = ; i < cnt; i++) {
for (int j = ; j < ( << n); j++) {
dp[i][j] = maxn[j] = max(dp[i][j], maxn[j]);
if (dp[i][j] < ) continue;
int pos=binary_s(i);
int pre = -;
for (int z = pos; z < tot; z++) {
if (pre == - || pre == ax[z].x) pre = ax[z].x;
else break;
int x1 = ax[z].y;
int jj = j | ( << ax[z].id);
int sum = dp[i][j] + ax[z].sud;
dp[x1][jj] = max(dp[x1][jj], sum);
}
}
}
if (maxn[( << n) - ] >= ) printf("%d\n", maxn[( << n) - ]);
else printf("-1\n");
return ;
}
E - Nature Reserve
题意:在二维坐标上,有动物的栖息地和一条河流,河流在y=0上,即为X轴。现在要建一个圆形的动物保护区,让动物都在里面,同时这个圆要求和X轴相切。因为只能相切,如果出现动物在X轴两侧的情况输出-1,即不能满足情况。
思路:我们二分半径,然后由于固定了与X轴相切,我们对于每一个点,就可以算出这个点在圆上的时候的圆心的极限距离。然后我们就可以求得每一个点的圆心的区间范围。然后所有点的区间范围都相交,那么证明这个半径可行,否则不可行。
代码:如果你的电脑和我的一样辣鸡,代码基本相同样例跑不出来,可能是精度的问题,建议您不要取很大的数字,取小点吧。
/*
I have a dream!A AC deram!!
orz orz orz orz orz orz orz orz orz orz orz
orz orz orz orz orz orz orz orz orz orz orz
orz orz orz orz orz orz orz orz orz orz orz */ #include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<stack>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e5 + ;
#define pa pair<int,int> inline int read()
{
int x = , f = ; char ch = getchar(); for (; !isdigit(ch); ch = getchar())if (ch == '-')f = -;
for (; isdigit(ch); ch = getchar())x = x * + ch - ''; return x * f;
} double x[maxn], y[maxn];
int N; bool check(long double R)
{
long double l = -100000000000000000.0, r = 100000000000000000.0, t;
for (int i = ; i <= N; i++)
{
if ( * R < y[i])
return ;
t = sqrt(R*R - (R - y[i])*(R - y[i]));
if (l < x[i]-t) l = x[i] - t;
if (r > t+x[i]) r = t + x[i];
}
return l < r;
} int main()
{
scanf("%d", &N);
for (int i = ; i <= N; i++)
scanf("%lf %lf", &x[i], &y[i]);
for (int i = ; i <= N; i++)
{
if (y[i] * y[N] < )
{
printf("-1\n");
return ;
}
y[i] = y[i] > ? y[i] : -y[i];
} long double l = , r = 100000000000000000.0, mid;
for(int i = ;i <= ;i++)
{
mid = (l + r) / 2.0;
if (check(mid))
r = mid;
else
l = mid;
}
printf("%.10Lf\n", mid); return ;
}
F - Graph And Its Complement
题意:给出n,a,b,问,是否有这样的一个图,有n个节点,分成a块,现将两两节点之间有边的把边删除,两两节点之间无边的建边,使得形成的图分成b块。如果有,输出YES,并且输出这个图的邻接矩阵,否则输出NO。这题难就难在是否能推出结论以及答案的输出。
思路:
任何一个图,不管分成多少块,经过上述操作后,必然变成一个联通图。
证:有n个节点,分成m块,任取一块,经过上述操作后,所取的这一块内的任意节点必定与其他块的所有节点相连!
这个结论换句话说就是,a和b里面,至少有一个数是1!知道这个结论就简单了,首先排除所有不含1的情况,然后,b==1的情况,我们将图分成a块,直接另前a-1块都只有一个节点,最后1块包含剩下的节点就行了。当然,对于a==1,只要将要输出反过来一下就可以了(注意,这里要讨论一下a和b都为1的情况,当n==2和n==3时,是不行的直接排除,其他情况都是可行的,特殊处理一下a和b都等于1的输出)
---------------------
作者:JIA-YAO
来源:CSDN
原文:https://blog.csdn.net/qq_41874469/article/details/80658410
代码:
#include "iostream"
#include "algorithm"
using namespace std;
int n,a,b;
char ch1='',ch2='';
int main() {
cin>>n>>a>>b;
if (a!=&&b!=||a==&&b==&&n<=&&n>=||a>n||b>n) {cout<<"NO"<<endl; return ;}
cout<<"YES"<<endl;
if (a==) swap(a,b), swap(ch1,ch2);
for (int i=;i<n;i++) {
for (int j=;j<n;j++) {
cout<<(i==j?'':(i+==j&&j>=a||j+==i&&i>=a?ch1:ch2));
}
cout<<endl;
}
}
2019 HZNU Winter Training Day 15 Comprehensive Training的更多相关文章
- 2019 HZNU Winter Training Day 14 Comprehensive Training
A - Choosing Capital for Treeland CodeForces - 219D 题意:有一颗单向边的树,要选取一个结点作为首都.要求是这个结点到其它结点,总共需要翻转的路径数量 ...
- 2019 HZNU Winter Training Day 13 Comprehensive Training
A.Jongmah CodeForces-1110D 题意:你在玩一个数字游戏,有一堆写在瓦片上的数字,希望你能组成最多的三元组(三个数字相同,或顺子). 这题用到的方法是动态规划.f[i][j] ...
- 2019 wannafly winter camp day 3
2019 wannafly winter camp day 3 J 操作S等价于将S串取反,然后依次遍历取反后的串,每次加入新字符a,当前的串是T,那么这次操作之后的串就是TaT.这是第一次转化. 涉 ...
- 2019 wannafly winter camp
2019 wannafly winter camp Name Rank Solved A B C D E F G H I J K day1 9 5/11 O O O O O day2 5 3/11 O ...
- 【Android Developers Training】 15. 启动一个Activity
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- (诡异Floyd&自环)MZ Training 2014 #15 E题(POJ 2240)
你们见过这么诡异的FLOYD吗? 先上题. [Description] 货币的汇率存在差异.比如,如果1美元购买0.5英镑,1英镑买10法郎.而1法国法郎买0.21美元.然后,通过转换货币,一个聪明的 ...
- 2019 CCPC-Wannafly Winter Camp Day5(Div2, onsite)
solve 5/11 补题:7/11 A Cactus Draw Code:zz Thinking :zz 题意:要在n*n的网格内画上一棵节点数为n树,使得没有边相交. 很好想的构造题,因为网格有n ...
- 2019 wannafly winter camp day5-8代码库
目录 day5 5H div2 Nested Tree (树形dp) 5F div2 Kropki (状压dp) 5J div1 Special Judge (计算几何) 5I div1 Sortin ...
- 2019 wannafly winter camp day1-4代码库
目录 day1 F div1 爬爬爬山 (最短路) B div2 吃豆豆 (dp) J div2 夺宝奇兵(暴力) J div1 夺宝奇兵 (权值线段树) C div1 拆拆拆数 E div1 流流流 ...
随机推荐
- Android开发进阶——自定义View的使用及其原理探索
在Android开发中,系统提供给我们的UI控件是有限的,当我们需要使用一些特殊的控件的时候,只靠系统提供的控件,可能无法达到我们想要的效果,这时,就需要我们自定义一些控件,来完成我们想要的效果了.下 ...
- 最全数据分析资料汇总(含python、爬虫、数据库、大数据、tableau、统计学等)
一.Python基础 Python简明教程(Python3) Python3.7.4官方中文文档 Python标准库中文版 廖雪峰 Python 3 中文教程 Python 3.3 官方教程中文版 P ...
- spring-boot项目的docker集成化部署(一)
目录 spring-boot项目的docker集成化部署 前言 基本思路与方案 基本步骤 准备源码 服务器和基础环境 结语 1. 本文总结: 2. 后期优化: spring-boot项目的docker ...
- kali Metasploit 连接 Postgresql 默认密码
使用 metasploit 时, 1. 启动 postgresql service postgresql start 2. 自行测试 postgresql 是否安装成功 根据需要,自行 修改 post ...
- 【原创】POI操作Excel导入导出工具类ExcelUtil
关于本类线程安全性的解释: 多数工具方法不涉及共享变量问题,至于添加合并单元格方法addMergeArea,使用ThreadLocal变量存储合并数据,ThreadLocal内部借用Thread.Th ...
- 使用webstorm调试node.js
折腾半天,还是webstorm顺手,但也遇到一些小问题. 1.代码补全问题 nodeJS自身的补全 File->Project Setting->JavaScript->Librar ...
- 【0805 | Day 8】Python进阶(二)
列表类型内置方法 一.列表类型内置方法(list) 用途:多个爱好.多个武器.多种化妆品 定义:[ ]内可以有多个任意类型的值,逗号分隔元素 # my_boy_friend = list(['jaso ...
- egg-sequelize-ts 插件
egg-sequelize-ts plugin 目的 (Purpose) 能让使用 typescript 编写的 egg.js 项目中能够使用 sequelize方法,并同时得到egg.js所赋予的功 ...
- 约会安排 HDU - 4553(线段树区间查询,区间修改,区间合并)
题目: 寒假来了,又到了小明和女神们约会的季节. 小明虽为屌丝级码农,但非常活跃,女神们常常在小明网上的大段发言后热情回复“呵呵”,所以,小明的最爱就是和女神们约会.与此同时,也有很多基友找他开黑, ...
- 解决socket粘包的两种low版模式 os.popen()和struct模块
os.popen()模式 server端 import socket import os phone = socket.socket() # 实例化一个socket对象 phone.bind((&qu ...