首页 技术 正文
技术 2022年11月17日
0 收藏 587 点赞 2,859 浏览 9011 个字

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 longusing 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;
}
}
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,088
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,565
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,413
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,186
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,822
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,905