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. ios开发--给应用添加新的字体的方法

    1.网上搜索字体文件(后缀名为.ttf,或.odf) 2.把字体库导入到工程的resouce中 3.在程序添加以下代码 输出所有字体 NSArray *familyNames = [UIFont fa ...

  2. android 基于wifi模块通信开发

    这篇文章主要是我写完手机与wifi模块通信后所用来总结编写过程的文章,下面,我分几点来说一下编写的大概流程. 一.拉出按钮控件并设置它的点击事件 二.设置wifi权限 三.打开和关闭wifi 四.扫描 ...

  3. 再记一次经典Net程序的逆向过程

    1.前言 上次发完,有网友问了一个问题:如果不绕过编译,而是直接编译怎么办? 记一次Net软件逆向的过程:https://www.cnblogs.com/dotnetcrazy/p/10142315. ...

  4. 搭建nexus私服

    一.安装 1.从网上下载nexus软件https://www.sonatype.com/download-oss-sonatype  下载Nexus Repository Manager OSS软件包 ...

  5. 从原理层面掌握@SessionAttribute的使用【一起学Spring MVC】

    每篇一句 不是你当上了火影大家就认可你,而是大家都认可你才能当上火影 前言 该注解顾名思义,作用是将Model中的属性同步到session会话当中,方便在下一次请求中使用(比如重定向场景~). 虽然说 ...

  6. android ——Toolbar

    Toolbar是我看material design内容的第一个 官方文档:https://developer.android.com/reference/android/support/v7/widg ...

  7. Docker 前沿概述

    目录 Docker 前沿概述 什么是Docker? Docker的基本概念 容器(Container) -- 镜像运行时的实体 镜像(Image) -- 一个特殊的文件系统 仓库(Repository ...

  8. AVL树(查找、插入、删除)——C语言

    AVL树 平衡二叉查找树(Self-balancing binary search tree)又被称为AVL树(AVL树是根据它的发明者G. M. Adelson-Velskii和E. M. Land ...

  9. JAVA的初体验

    jdk的地址:https://www.oracle.com/technetwork/java/javase/downloads/index.html 第一步:找到相应的JAVA SE版本,点击down ...

  10. LD_PRELOAD和ld --wrap

    前言 LD_PRELOAD和ld --wrap都能实现不修改原始代码,替换指定函数的实现.通常我们会使用这些方法,替换如malloc)()/free().read()/write()等函数,并在替换函 ...