2019-12-30 21:27阅读: 295评论: 0推荐: 2

Good Bye 2019

A. Card Game (CF 1270 A)

题目大意

两个人各持有k1k2张牌,牌序号唯一且在范围1~n其中n=k1+k2。一次操作两个各亮出一张牌,谁牌序号大,谁拿对方的牌,最后没牌者输,问先手是否必赢。

解题思路

很显然谁持有最大牌谁赢......

但是tourist能在一分钟内读完题并敲好代码提交过了真是太强了。

神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<PII> VPII;
typedef vector<LL> VL;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
int n,k1,k2;
int main(void) {
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int kase; read(kase);
for (int i = 1; i <= kase; i++) {
//printf("Case #%d: ", i);
read(n);
read(k1);
read(k2);
bool qwq=false;
for(int u,i=1;i<=k1;++i){
read(u);
if (u==n) qwq=true;
}
for(int u,i=1;i<=k2;++i){
read(u);
}
if (qwq) printf("YES\n");
else printf("NO\n");
}
return 0;
}


B. Interesting Subarray (CF 1270 B)

题目大意

给定一个长度为n的数组a,问是否存在某个区间[l,r],有maxmink,其中max=maxi[l,r](ai)min=mini[l,r](ai)k=rl+1,存在则输出YES并输出任意一个符合要求的区间,否则输出NO.

解题思路

我们考虑一个符合题目条件的区间[l,r],其中最大值和最小值在端点处是最优的选择,不失一般性,我们设最大值在r处,最小值在l处,则maxmin=(max1max2)+(max2max3)+...+(maxk1maxk)k,从中我们可以看出至少有一个maximaxi+1>1,才能有该不等式成立,那也一定有至少一个位置iabs(aiai+1)2才行。

神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<PII> VPII;
typedef vector<LL> VL;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
int n,u,v;
int main(void) {
//ios::sync_with_stdio(false);
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int kase; read(kase);
for (int i = 1; i <= kase; i++) {
//printf("Case #%d: ", i);
read(n);
read(u);
bool qwq=false;
int l=0;
for(int i=2;i<=n;++i){
read(v);
if (ABS(v-u)>1) {qwq=true;l=i-1;}
u=v;
}
if (qwq) printf("YES\n%d %d\n",l,l+1);
else printf("NO\n");
}
return 0;
}


C. Make Good (CF 1270 C)

题目大意

给定n个正整数,设n个数的和为sum,异或为x,若sum=2x则这个序列是good的,如果不是good,最多可增加三个正整数,使得这个序列变成good,求添加数的个数以及数的大小。

解题思路

首先sum一定要是偶数,否则我们先加一个数1,然后再考虑sumx大小。

注意到异或两次同一个数相当于不变,那么如果sum<2x,那么我们只要再增加两个同样的数qwq=2xsum2,这样x不变,而sum也变成了2x

如果sum>2x,我们再一开始增加一个超大超大的数,让sum<2x即可,由于sum1015,那我们就增加一个1016的数,即250,如果sum是奇数,就加250+1,然后根据上面的情况即可。

对应代码为注释部分。

这题还有另一种加法,即加两个数xsum+x,这样和就变成2(sum+x),异或值变成sum+x,这样也符合题意。

还有最优的只用加一个数的方法(如果sumx)
即先x=2x后,从低位到高位逐一比较sumx的每一位是否相等,如果不相等则添一个在该位为1的数,添这个数后只会影响sumx的高位,不会影响低位,然后把这些数加起来就得到我们要的那一个数了。

神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<PII> VPII;
typedef vector<LL> VL;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
int main(void) {
//ios::sync_with_stdio(false);
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int kase; read(kase);
for (int i = 1; i <= kase; i++) {
//printf("Case #%d: ", i);
int n;
LL sum,xx,u,a;
read(n);
sum=xx=0;
for(int i=1;i<=n;++i){
read(u);
sum+=u;
xx=xx^u;
}
printf("2\n%lld %lld\n",xx,xx+sum); //两个数
/*
一个数
xx<<=1;
LL ans=0;
int id=0;
while(sum||xx){
if ((sum^xx)&1){
ans+=(1ll<<id);
sum++;
xx^=2;
}
sum>>=1;
xx>>=1;
++id;
}
if (ans) printf("1\n%lld\n",ans);
else printf("0\n\n");
*/
/*
三个数
if ((xx<<1ll)==sum) printf("0\n\n");
else{
a=(1ll<<50ll);
if (sum&1ll) a=a|1ll;
sum+=a;
xx=(xx^a);
xx<<=1;
LL qwq=xx-sum;
printf("3\n%lld %lld %lld\n",a,(qwq>>1),(qwq>>1));
}
*/
}
return 0;
}


D. Strange Device (CF 1270 D)

题目大意

交互题。

给定nk,以及一个你并不知道长度为n的数俩俩不同的数列和m,每次你可以问k个互不相同的下标,对方会告诉你这些下标对应的值里,从小到大排列第m个小数的位置和值。不能问多于n次。最后你的程序要猜出m值。

解题思路

一开始妄图想找到k个数然后问它们一波得到m值结果不可行。然后妄图用并查集维护每个数在m的左边还是右边发现数太多了不可控qwq所以我们要考虑少点的数,比如就前k+1个数,每次我们选这其中的k个数,相当于把其中的一个数从k+1个数中剔除,然后我们考虑这个剔除的数对第m个数的影响。

假设在这k+1个数中,第m个数的值为a,则如果剔除的一个数i小于等于a,则第m个数会变成另一个数b,如果大于a,则第m个数还是a。纵观我们剔除k+1次的结果,可以知道数a会出现k+1m,而数b会出现m次,于是我们统计较大的数出现的次数就是答案m

神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<PII> VPII;
typedef vector<LL> VL;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
int main(void) {
//ios::sync_with_stdio(false);
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
int n,k;
read(n);
read(k);
vector<bool> sign(k+2,false);
int ma=0,cnt=0;
for(int i=1;i<=k+1;++i){
sign[i]=true;
sign[i-1]=false;
printf("? ");
for(int j=1;j<=k+1;++j) if (!sign[j]) printf("%d ",j);
puts("");
fflush(stdout);
int u,v;
read(u);read(v);
if (ma<v){cnt=1;ma=v;}else if (ma==v) ++cnt;
}
printf("! %d\n",cnt);
fflush(stdout);
return 0;
}


E. Divide Points (CF 1270 E)

题目大意

给出n个点坐标,要求将它们分成两个非空集AB,使得没有同组的点距离与不同组的点距离相同。

解题思路

由于n不大,一开始想着枚举所有距离然后排序,把有相同距离的点对分到同一个组,然后构造了两个反例qwq,一个是所有点分布呈以一个点为圆心的圆上,另一个是两个圆emmmmm。

我们试着根据点的坐标性质进行分类,所有点坐标在mod 2的意义下我们可以分成四类:(0,0) (0,1) (1,0) (1,1),如果我们对于属于同类的点都放在一个集合里时,它们的xy坐标差一定是偶数,这样它们的距离的平方就一定是偶数,这启示我们,如果不同组的点距离的平方是奇数的话,那么就一定没有同组的点距离与不同组的点距离相同。经过分析我们可以知道,点坐标属于(0,0)(1,1)的点与点坐标属于(1,0)(0,1)的点的距离一定是奇数。那么我们就把点坐标属于(0,0)(1,1)放在A,点坐标属于(1,0)(0,1)放在B即可。再综合一下就是点坐标和是偶数的放在A,点坐标和是奇数的放在B

那要是没有点坐标和是奇数或偶数的怎么办?我们先选定一个点为原点进行整体平移,这样就一定有坐标和为偶数的点。如果没有坐标和是奇数点的话,此时所有点坐标和都为偶数,但我们注意到,如果点属于(0,0)的,它们点的距离的平方是4的倍数,而点属于(1,1)的,它们点的距离的平方除以4会余2,这样我们就把(0,0)放在A(1,1)放在B即可。若没有(1,1)的点的话,我们对全部坐标都除以2,这样所有点的距离的平方都会除以4,但该相等的还是相等,不相等的还是不相等,不影响我们的判断。由于坐标最大不超过106,故除以2的次数不会超过log2106,重复以上操作即可。

神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<PII> VPII;
typedef vector<LL> VL;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
int main(void) {
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
/* int kase; read(kase);
for (int i = 1; i <= kase; i++) {
printf("Case #%d: ", i);
} */
int n;
read(n);
vector<int>x,y;
for(int u,v,i=0;i<n;++i){
read(u);read(v);
x.push_back(u);
y.push_back(v);
}
for(int i=1;i<n;++i){
x[i]-=x[0];
y[i]-=y[0];
}
x[0]=y[0]=0;
while(1){
vector<int> qwq;
for(int i=1;i<n;++i)
if ((x[i]+y[i])&1) qwq.push_back(i);
if (!qwq.empty()){
printf("%d\n",(int)qwq.size());
for(int i:qwq){
printf("%d ",i+1);
}
puts("");
return 0;
}
for(int i=1;i<n;++i)
if (x[i]&1) qwq.push_back(i);
if (!qwq.empty()){
printf("%d\n",(int)qwq.size());
for(int i:qwq){
printf("%d ",i+1);
}
puts("");
return 0;
}
for(int i=1;i<n;++i){
x[i]>>=1;
y[i]>>=1;
}
}
return 0;
}


G. Subset with Zero Sum (CF 1270 G)

题目大意

给定一个长度为n的数组a,其中第i个元素ai满足:inaii1,请选择一些数使得它们和为0,并输出它们的位置。保证有解,若有多解,输出任意一种即可。

解题思路

这题思路清奇......
我们将inaii1变形得到1iain
注意到iai仍在[1,n]的范围,我们构造一张有向图,第i个点连向第iai个点。由于每个点都有条出边,那么一定会有一个环,我们考虑环上的点i1,i2,i3,...,ik,分别有:

  • i1ai1=i2
  • i2ai2=i3
  • i3ai3=i4
  • i4ai4=i5
  • ......
  • ikaik=i1

累加得ai1+ai2+ai3+......+aik=0这样我们就找到了一组符合题目要求的i1,i2,i3,...,ik
(这脑洞是有多大……)

神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<PII> VPII;
typedef vector<LL> VL;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
int main(void) {
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int kase; read(kase);
for (int i = 1; i <= kase; i++) {
//printf("Case #%d: ", i);
int n;
read(n);
vector<int> a(n+1);
for(int i=1;i<=n;++i)
read(a[i]);
vector<bool> visit(n+1,false);
int qwq=1;
while(!visit[qwq]){
visit[qwq]=true;
qwq=qwq-a[qwq];
}
vector<int> ans;
ans.push_back(qwq);
int qaq=qwq-a[qwq];
while(qaq!=qwq){
ans.push_back(qaq);
qaq=qaq-a[qaq];
}
printf("%d\n",(int)ans.size());
for(int i:ans) printf("%d ",i);
puts("");
}
return 0;
}


May 2020 will be the year of high ratings for the hard workers.

本文作者:~Lanly~

本文链接:https://www.cnblogs.com/Lanly/p/12121823.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   ~Lanly~  阅读(295)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.