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的更多相关文章

  1. 2019 HZNU Winter Training Day 14 Comprehensive Training

    A - Choosing Capital for Treeland CodeForces - 219D 题意:有一颗单向边的树,要选取一个结点作为首都.要求是这个结点到其它结点,总共需要翻转的路径数量 ...

  2. 2019 HZNU Winter Training Day 13 Comprehensive Training

    A.Jongmah   CodeForces-1110D 题意:你在玩一个数字游戏,有一堆写在瓦片上的数字,希望你能组成最多的三元组(三个数字相同,或顺子). 这题用到的方法是动态规划.f[i][j] ...

  3. 2019 wannafly winter camp day 3

    2019 wannafly winter camp day 3 J 操作S等价于将S串取反,然后依次遍历取反后的串,每次加入新字符a,当前的串是T,那么这次操作之后的串就是TaT.这是第一次转化. 涉 ...

  4. 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 ...

  5. 【Android Developers Training】 15. 启动一个Activity

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  6. (诡异Floyd&amp;自环)MZ Training 2014 #15 E题(POJ 2240)

    你们见过这么诡异的FLOYD吗? 先上题. [Description] 货币的汇率存在差异.比如,如果1美元购买0.5英镑,1英镑买10法郎.而1法国法郎买0.21美元.然后,通过转换货币,一个聪明的 ...

  7. 2019 CCPC-Wannafly Winter Camp Day5(Div2, onsite)

    solve 5/11 补题:7/11 A Cactus Draw Code:zz Thinking :zz 题意:要在n*n的网格内画上一棵节点数为n树,使得没有边相交. 很好想的构造题,因为网格有n ...

  8. 2019 wannafly winter camp day5-8代码库

    目录 day5 5H div2 Nested Tree (树形dp) 5F div2 Kropki (状压dp) 5J div1 Special Judge (计算几何) 5I div1 Sortin ...

  9. 2019 wannafly winter camp day1-4代码库

    目录 day1 F div1 爬爬爬山 (最短路) B div2 吃豆豆 (dp) J div2 夺宝奇兵(暴力) J div1 夺宝奇兵 (权值线段树) C div1 拆拆拆数 E div1 流流流 ...

随机推荐

  1. 【nodejs原理&源码赏析(9)】用node-ssh实现轻量级自动化部署

    目录 一. 需求描述 二. 预备知识 IP+端口访问 域名访问 三. Nodejs应用的手动部署 四. 基于nodejs的自动部署 4.1 package.json中的scripts 4.2 自动化发 ...

  2. SpringMvc新建实例配置

    一.创建项目: 1.建立新的动态web项目: 2.为项目命名为:SpringMVC_01 3.添加tomcat运行时环境\依赖库  如果是MyEclipse的话创建web项目时就不需要此步骤 右键项目 ...

  3. JDK的命令行工具系列 (一) jps、jstat

    概述 在我们进行故障定位和性能分析时, 可以使用Java Dump(也叫Dump文件)来帮助排查问题, 它记录了JVM运行期间的内存占用和线程执行等情况.其中Heap Dump文件是二进制格式, 它保 ...

  4. JavaScript ES6和ES5闭包的小demo

    版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 (Creative Commons) 可能有些小伙伴不知道ES6的写法,这儿先填写一个小例子 let conn ...

  5. spark shuffle写操作三部曲之BypassMergeSortShuffleWriter

    前言 再上一篇文章 spark shuffle的写操作之准备工作 中,主要介绍了 spark shuffle的准备工作,本篇文章主要介绍spark shuffle使用BypassMergeSortSh ...

  6. lvs+keepalived 高可用及负载均衡

    一.环境准备 VIP:10.18.43.30 dr1:10.18.43.10 dr2:10.18.43.20 web1:10.18.43.13 web2:10.18.43.14 结构图 (一).预处理 ...

  7. Unity基础之:UnityAPI的学习

    版权声明: 本文原创发布于博客园"优梦创客"的博客空间(网址:http://www.cnblogs.com/raymondking123/)以及微信公众号"优梦创客&qu ...

  8. 关于Linux的简单介绍

    Linux: 诞生日期:1991年 开发者:林纳斯·托瓦茨 特点:免费,开源    发行版本:centos|red Hat|Ubuntu|红旗等    思想:一切都是文件 重要文件目录 bin:二进制 ...

  9. ES 26 - 通过partial update局部更新索引文档 (partial update增量修改原理)

    目录 1 什么是partial update 1.1 全量修改文档的原理 1.2 修改指定field的思路 1.3 partial update的优势 1.4 partial update的使用 2 ...

  10. 浅谈IDEA集成SSM框架(SpringMVC+Spring+MyBatis)

    前言 学习完MyBatis,Spring,SpringMVC之后,我们需要做的就是将这三者联系起来,Spring实现业务对象管理,Spring MVC负责请求的转发和视图管理, MyBatis作为数据 ...