前言
太久没打,手速/脑力都不行啦~~
- 否则,去掉前缀/后缀
int n,m,l,r,ans;
ll s;
int main() {
int _;qr(_); while(_--) {
qr(n); qr(m); l=r=ans=-1; s=0;
for(int i=1,x;i<=n;i++) {
qr(x);
if(x%m) {
s+=x;
if(l==-1) l=i;
r=i;
}
}
if(s%m) pr2(n);
else if(l==-1) puts("-1");
else pr2(n-min(l,n-r+1));
}
return 0;
}
若 是一个峰值,则保留.
int n,p[N],f[N],cnt;
int main() {
int _;qr(_); while(_--) {
qr(n);
for(int i=1;i<=n;i++) qr(p[i]);
f[cnt=1]=p[1];
for(int pre=1,i=2;i<n;i++) {
if((p[i]>p[pre])^(p[i+1]>p[i]))f[++cnt]=p[i],pre=i;
}
f[++cnt]=p[n]; pr2(cnt);
for(int i=1;i<=cnt;i++) pr1(f[i]);
puts("");
}
return 0;
}
.
前
个数一定能构造出答案
.
我们用一个队列维护一下还未取值的点,在
发生变化的时候倒序插入即可.
int n,a[N],m=1e6,q[N],l=1,r,f[N];
int main() {
qr(n);
for(int i=1;i<=n;i++)
qr(a[i]);
int cnt=0;
for(int i=1;i<=n;i++) {
q[++r]=i; cnt++;
if(a[i]^a[i-1]) {
int x=a[i],y=a[i-1];
while(cnt&&x>y+1) f[q[l++]]=--x,cnt--;
f[q[r--]]=y; cnt--;
if(cnt<0) puts("-1"),exit(0);
}
}
while(cnt) f[q[l++]]=m,cnt--;
for(int i=1;i<=n;i++) pr1(f[i]);
return 0;
}
如果是一棵树,那么用黑白染色,然后取较大的集合一定能解决
.
否则,找到一个简单环也一定能求解.
设环的大小为
.
- ,输出环.
- ,隔着输出 个数即可.
#include<map>
#include<set>
#include<ctime>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define lc (x<<1)
#define rc (x<<1|1)
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
#define mk make_pair
#define pi pair<int,int>
#define pb push_back
#define IT iterator
#define SZ(a) ((int)a.size())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N=1e5+10,size=1<<20,mod=998244353;
//char buf[size],*p1=buf,*p2=buf;
template<class o> void qr(o &x) {
char c=gc; x=0; int f=1;
while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
while(isdigit(c)) x=x*10+c-'0',c=gc;
x*=f;
}
template<class o> void qw(o x) {
if(x/10) qw(x/10);
putchar(x%10+'0');
}
template<class o> void pr1(o x) {
if(x<0)x=-x,putchar('-');
qw(x); putchar(' ');
}
template<class o> void pr2(o x) {
if(x<0)x=-x,putchar('-');
qw(x); puts("");
}
int n,m,q,pos[N],sta[N],top,cir[N],cnt;
vector<int> e[N],col[2];
void add(int x,int y) {e[x].push_back(y);}
bool dfs(int x) {
sta[++top]=x; pos[x]=top; col[top&1].push_back(x);
int low=-1;
for(int y:e[x])
if(pos[y]&&top-pos[y]>1) low=max(low,pos[y]);//找一个简单环.中间一定没有边(否则前面就已经找到环了)
if(~low) {
for(int i=low;i<=top;i++)
cir[++cnt]=sta[i];
return 1;
}
for(int y:e[x])
if(!pos[y]&&dfs(y)) return 1;
top--;return 0;
}
int main() {
qr(n); qr(m); qr(q);
for(int i=1,x,y;i<=m;i++) {
qr(x); qr(y);
add(x,y); add(y,x);
}
dfs(1);
if(cnt) {//如果找到环,那么一定有解
if(cnt<=q) {
puts("2");pr2(cnt);
while(cnt)
pr1(cir[cnt--]);
}
else {
puts("1");
for(int i=1;i<=q;i+=2)
pr1(cir[i]);
}
}
else {
puts("1");
q=(q-1)/2+1;
int p=(col[0].size()<col[1].size()),c=0;
for(auto i:col[p]) {
pr1(i);
if(++c==q) break;
}
}
return 0;
}
注释讲得较清楚了吧…
看完代码后你可能觉得这个代码可能会出现询问 次的疑问.(即前面找含0的二元组 次,最后求解 次.中间部分你可以认为 次一定能求解,所以不用管它)
for(int i=3;i<=n;i++) {
int j=ask(y,i);
if(z>j) x=i,z=j;//x此时一定不为0
else if(z==j) y=i,z=ask(x,y);//y此时一定不为0.(反证法)
}
你可能认为if(z==j) y=i,z=ask(x,y);
的运行次数为
.
其实不然,
当且仅当
的真子集,所以
那么二进制下一的个数不断减小,次数至多为
.所以大可不必担心…
#include<map>
#include<set>
#include<ctime>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define lc (x<<1)
#define rc (x<<1|1)
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
#define mk make_pair
#define pi pair<int,int>
#define pb push_back
#define IT iterator
#define SZ(a) ((int)a.size())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N=1<<11|10,size=1<<20,mod=998244353;
//char buf[size],*p1=buf,*p2=buf;
template<class o> void qr(o &x) {
char c=gc; x=0; int f=1;
while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
while(isdigit(c)) x=x*10+c-'0',c=gc;
x*=f;
}
template<class o> void qw(o x) {
if(x/10) qw(x/10);
putchar(x%10+'0');
}
template<class o> void pr1(o x) {
if(x<0)x=-x,putchar('-');
qw(x); putchar(' ');
}
template<class o> void pr2(o x) {
if(x<0)x=-x,putchar('-');
qw(x); puts("");
}
int n,x,y,z,vis[N],ans[N];
map<pi,int> s;
int ask(int x,int y) {
if(x>y) swap(x,y);
pi t=mk(x,y);
if(s.count(t)) return s[t];
printf("? %d %d\n",x,y); fflush(stdout);
qr(x); if(x==-1) exit(0);
return s[t]=x;
}
int main() {
srand(time(0));
qr(n); x=1; y=2; z=ask(x,y);
//此算法的重点是找到0.找到0后,我们与每个位置|一下即可得到每个位置的答案
//我们要让 x,y 中存在0.
for(int i=3;i<=n;i++) {
int j=ask(y,i);
if(z>j) x=i,z=j;//x此时一定不为0
else if(z==j) y=i,z=ask(x,y);//y此时一定不为0.(反证法)
}
//此时我们要确定那个是0.
int zero=0;
while(!zero) {
int t=rand()%n+1;
if(t==x||t==y) continue;
if(ask(t,x)<ask(t,y)) zero=x;
else if(ask(t,x)>ask(t,y)) zero=y;
//设x|y=k,则当k为t的真子集时,ask(t,x)==ask(t,y).
//当k为二的次幂时,相等的次数最多.但是不相等的概率依然有0.5.
//所以,很快即可得到答案.(100次都找不到的概率=1-(0.5)^100,所以不会那么背吧...)
}
for(int i=1;i<=n;i++) {
if(i==zero) ans[i]=0;
else ans[i]=ask(i,zero);
}
printf("! ");
for(int i=1;i<=n;i++) pr1(ans[i]);
return 0;
}