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 流流流 ...
随机推荐
- 华为matebook14vm虚拟机错误
1.创建时显示不支持64位虚拟机 测试环境: 华为matebook14 window10 专业工作站版 1903 问题描述: 创建虚拟机时显示:此主机不支持64位解决方案 问题参考: 参考1 ...
- RocketMQ中NameServer的启动
在RocketMQ中,使用NamesrvStartup作为启动类 主函数作为其启动的入口: public static void main(String[] args) { main0(args); ...
- 破解EFCore扩展Dll --- Z.EntityFramework.Extensions.EFCore
安装 Z.EntityFramework.Extensions.EFCore Install-Package Z.EntityFramework.Extensions.EFCore -Version ...
- 自定义 EditText 样式
极力推荐文章:欢迎收藏 Android 干货分享 阅读五分钟,每日十点,和您一起终身学习,这里是程序员Android 本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以 ...
- Java 设计模式 – Observer 观察者模式
目录 [隐藏] 1 代码 1.1 观察者接口: 1.2 被观察者: 1.3 观众类 : 1.4 电影类: 1.5 效果如下: 代码 说明都在注释: 观察者接口: package ObserverMod ...
- gdb调试和编译后运行结果不一致
今天在看代码时,遇到这么一段代码,我但是用g++编译了,运行发现有Segmentation fault. 然后就用gdb跟进去看看,可是gdb却正常执行了.不知道什么原因. #include < ...
- 解决 Android 中出现依赖多个版本支持库的问题
在 app 的 build.gradle 中引入依赖时发现如下错误: All com.android.support libraries must use the exact same version ...
- Flink 源码解析 —— 如何获取 JobGraph?
JobGraph https://t.zsxq.com/naaMf6y 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Mac 上搭建 F ...
- 996工作制?不如花点时间学知识!北栀暗影教你如何用WordPress搭建专业网站
很多70后.80后小时候都看过这样一部动画片-<半夜鸡叫>.讲的是地主"周扒皮"为了长工们能多干些活,半夜三更起来学鸡叫让长工劳动(卖身契上规定:鸡叫就得起床干活劳动) ...
- redis 有没有ACID事务
看redis官网的介绍: redis确实是有事务的,但是和传统的ACID是否相同呢? 原子性(Atomicity) 原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生. 一致 ...