Problems
# | Name | ||
---|---|---|---|
A | Nezzar and Colorful Balls | ![]() ![]() |
![]() |
B | Nezzar and Lucky Number | ![]() ![]() |
![]() |
C | Nezzar and Symmetric Array | ![]() ![]() |
![]() |
D | Nezzar and Board | ![]() ![]() |
![]() |
E | Nezzar and Binary String | ![]() ![]() |
![]() |
F | Nezzar and Nice Beatmap | ![]() ![]() |
![]() |
Solutions
A Nezzar and Colorful Balls
题意:给出一个不下降序列,要求将其分成尽可能少的严格上升子序列。
引理:设不下降序列中相同值最多的值数 \(=col\) , 则 \(ans=col.\)
证明:不妨把不下降序列画成这样一张图。
假设 \(a[i]\) 最多。
-
\(<col\) 的解都不可行:因为严格上升子序列不能同时存在 多个 \(a[i]\), 因此每个严格上升子序列至多有一个 \(a[i]\), 而 \(a[i]\) 共有 \(col\) 个,所以至少分 \(col\) 个。
-
可以构造出一组解使 \(ans=col\) . 如图
每个严格上升子序列选择颜色相同的方块即可。
Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N=256;
int n,T;
int a[N];
int main()
{
// freopen("1.in","r",stdin);
int i;
scanf("%d",&T);
while(T--) {
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
int cnt=1,ans=1;
for(i=2;i<=n;i++) {
if(a[i]==a[i-1]) ans=max(ans,++cnt);
else cnt=1;
}
ans=max(ans,cnt);
printf("%d\n",ans);
}
return 0;
}
B Nezzar and Lucky Number
题意:Nezzar's favorite digit among 1,…,9 is d. He calls a positive integer lucky if d occurs at least once in its decimal representation.
性质 1:数较大时必存在。
性质 2:若 \(x\) 可以,\(y\) 可以,则 \(x+y\) 可以。
那么对于 \(i\)
- 要么 \(i\) 本身可以。
- 要么枚举 \(j\) ,看是否存在 \(j,i-j\) 都可。
因此小范围打表,大范围直接判断即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N=10000;
bool haved(int num,int d)
{
while(num) {
int x=num%10;
num/=10;
if(x==d) return true;
}
return false;
}
int T,n,d;
bool st[N];
int main()
{
// freopen("1.in","r",stdin);
int i,j,x;
scanf("%d",&T);
while(T--) {
memset(st,0,sizeof st);
scanf("%d%d",&n,&d);
for(i=1;i<N;i++) {
if(haved(i,d)) st[i]=true;
else {
for(j=1;j<i;j++)
if(st[j] && st[i-j]) {
st[i]=true;
break;
}
if(j==i) st[i]=false;
}
}
while(n--) {
scanf("%d",&x);
if(x>=N || (x<N && st[x])) puts("YES");
else puts("NO");
}
}
return 0;
}
C Nezzar and Symmetric Array
画数轴即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N=3e5+5;
int T,n;
LL d[N];
int main()
{
// freopen("1.in","r",stdin);
int i;
scanf("%d",&T);
while(T--) {
scanf("%d",&n);
for(i=1;i<=2*n;i++)
scanf("%lld",&d[i]);
sort(d+1,d+2*n+1);
bool ans=true;
for(i=1;i<=2*n && ans;i+=2)
if(d[i]!=d[i+1] || d[i]%2==1) ans=false;
for(i=3;i<=2*n && ans;i+=2)
if(d[i]==d[i-2]) ans=false;
LL sum=0,cur=0;
for(i=3;i<=2*n && ans;i+=2) {
if((d[i]-d[i-2])%(2*(i/2))) ans=false;
cur+=(d[i]-d[i-2])/(2*(i/2));
sum=sum+cur;
if(sum>=d[1]/2) {
ans=false;
break;
}
}
if(ans && (d[1]/2-sum)%n) ans=false;
if(ans) puts("YES");
else puts("NO");
}
return 0;
}
D Nezzar and Board
这个 D ,我做过类似的。
对 \(x\) (\(x\) 是 \(a[]\) 中的某个数) 单次变换: \(2\times a[i]-x\) 。
两次变换: \(2 \times a[j]-(2 \times a[i]-x)=x+2\times (a[j]-a[i])\)
令 \(b_{i,j}=2(a[j]-a[i])\)
若走偶数步 \(x+\sum c_{i,j} \times b_{i,j}=m, c_{i,j} \in Z\)
由贝祖定理:\(\sum c_{i,j} \times b_{i,j}\) 的取值集合为 \(\{kd|d=\gcd(b_{i,j}),k\in Z\}\)
\(d=\gcd(b_{i,j})=\gcd(b_{1,1},b_{1,2},...,b_{n,n})\)
\(=2 \times \gcd(a_{2}-a_{1},a_{3}-a_{1},...,a_{n-1}-a_{n})\)
\(=2 \times \gcd(a_{2}-a_{1},a_{3}-a_{2},...,a_{n}-a_{n-1})\)
判断是否有 \(a[i]\) 使 \(a[i]=m \: (\bmod d)\)
若走奇数步,考虑在偶数步上再添一步。
判断是否有 \(i,j\) 使 \(2\times a[j]-a[i]=m \: (\bmod d)\)
因为 \(d|2\times (a[j]-a[1])\) , 所以 \(2a_1=2a_j (\bmod d)\)
判断是否有 \(a[i]\) 使 \(2\times a[1]-a[i]=m \: (\bmod d)\)
时间 \(O(n\log n)\)
Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
LL gcd(LL a,LL b)
{
if(b==0) return a;
else return gcd(b,a%b);
}
const int N=2e5+5;
int T,n;
LL m;
LL a[N];
inline LL mabs(LL x)
{
if(x<0) return -x;
else return x;
}
int main()
{
// freopen("1.in","r",stdin);
int i;
scanf("%d",&T);
while(T--) {
scanf("%d%lld",&n,&m);
for(i=1;i<=n;i++)
scanf("%lld",&a[i]);
LL g=0;
for(i=2;i<=n;i++)
g=gcd(g,mabs(a[i]-a[i-1]));
g*=2;
m=(m%g+g)%g;
for(i=1;i<=n;i++)
if((a[i]%g+g)%g==m || ((2*a[1]-a[i])%g+g)%g==m)
break;
if(i<=n) puts("YES");
else puts("NO");
}
return 0;
}
E - Nezzar and Binary String
倒推的话每一步都是确定的。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
const int N=2e5+5;
struct Node
{
int sum,tag;
}t[4*N];
#define lc (now<<1)
#define rc (now<<1|1)
void pushup(int now)
{
t[now].sum=t[lc].sum+t[rc].sum;
}
void Addtag(int now,int key,int l,int r)
{
t[now].tag=key;
t[now].sum=key*(r-l+1);
}
void pushdown(int now,int l,int r)
{
if(t[now].tag==-1) return;
int mid=(l+r)>>1;
Addtag(lc,t[now].tag,l,mid);
Addtag(rc,t[now].tag,mid+1,r);
t[now].tag=-1;
}
void Modify(int now,int x,int y,int key,int l,int r)
{
if(x<=l && r<=y)
return Addtag(now,key,l,r);
pushdown(now,l,r);
int mid=(l+r)>>1;
if(x<=mid) Modify(lc,x,y,key,l,mid);
if(y>=mid+1) Modify(rc,x,y,key,mid+1,r);
pushup(now);
}
int query(int now,int x,int y,int l,int r)
{
if(x<=l && r<=y)
return t[now].sum;
pushdown(now,l,r);
int mid=(l+r)>>1,res=0;
if(x<=mid) res+=query(lc,x,y,l,mid);
if(y>=mid+1) res+=query(rc,x,y,mid+1,r);
return res;
}
void Build(int now,int a[],int l,int r)
{
t[now].tag=-1;
if(l==r) {
t[now].sum=a[l];
return;
}
int mid=(l+r)>>1;
Build(lc,a,l,mid);
Build(rc,a,mid+1,r);
pushup(now);
}
int T,n,m;
PII q[N];
int s[N],f[N];
char str[N];
int main()
{
// freopen("1.in","r",stdin);
int i;
int x,y,z;
scanf("%d",&T);
while(T--) {
scanf("%d%d",&n,&m);
scanf("%s",str+1);
for(i=1;i<=n;i++) s[i]=str[i]-'0';
scanf("%s",str+1);
for(i=1;i<=n;i++) f[i]=str[i]-'0';
for(i=1;i<=m;i++)
scanf("%d%d",&q[i].first,&q[i].second);
Build(1,f,1,n);
for(i=m;i>=1;i--) {
x=q[i].first; y=q[i].second;
z=query(1,x,y,1,n);
if(2*z==y-x+1) break; // NO;
else if(y-x+1-z>z) Modify(1,x,y,0,1,n);
else Modify(1,x,y,1,1,n);
}
if(i) {
puts("NO");
continue;
}
for(i=1;i<=n;i++)
if(query(1,i,i,1,n)!=s[i]) break;
if(i<=n) puts("NO");
else puts("YES");
}
return 0;
}
F - Nezzar and Nice Beatmap
正解思路:每个点选择最远的点连,根据 大角对大边
\(C->A->B\)
\(CB \leq CA\) -> \(\angle A \leq \angle B\) -> \(\angle A<90^{*}\)
然而我不知道为什么就那么想用模拟褪火 qwq.
大概就是普通的模拟退火加上一些奇怪的东西。
- \(calc()\) 在计算估价的同时求一个 \(suggest\) , 表示贡献最大(最烂)的点,下一次在 \(suggest\) 周围选择。
- 先把点坐标按照极值大的排序,然后构造出一组较优的解 \(1,n,2,n-1,3,n-2,...\)
- 降温系数一定要为 0.999。
Code:
#pragma GCC optimize(2)
#include<ctime>
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<LL,LL> PLL;
typedef PLL Point;
typedef PLL Vector;
#define x first
#define y second
Vector operator-(Vector a,Vector b) { return Vector(a.x-b.x,a.y-b.y); }
LL dot(Vector a,Vector b) { return a.x*b.x+a.y*b.y; }
const int N=1e4+5;
const double INF=1e18;
int n;
Point a[N],b[N],c[N];
bool st[N];
int suggest;
void print()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) {
if(a[i]==b[j] && !st[j]) {
st[j]=true;
printf("%d ",j);
break;
}
}
exit(0);
}
double calc()
{
// for(int i=1;i<=n;i++)
// printf("%lld %lld\n",a[i].x,a[i].y);
// printf("\n");
double res=0,t,ms=-INF;
bool flag=true;
for(int i=2;i<=n-1;i++) {
t=dot(a[i-1]-a[i],a[i+1]-a[i]);
if(t<=0) {
flag=false;
res+=-t+1;
if(-t+1>ms) suggest=i,ms=-t+1;
}
}
if(flag) print();
// printf("%lld\n",res);
return res;
}
double rnd(double l,double r)
{
return rand()*(r-l)/RAND_MAX+l;
}
LL f(int x)
{
if(x>=n || x<=1) return 0;
else {
LL t=dot(a[x-1]-a[x],a[x+1]-a[x]);
if(t>0) return 0;
else return -t+1;
}
}
LL add(int x,int y)
{
static vector<int> v; v.clear();
v.push_back(x-1); v.push_back(x); v.push_back(x+1);
v.push_back(y-1); v.push_back(y); v.push_back(y+1);
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
LL res=0;
for(int i=0;i<(int)v.size();i++)
res+=f(v[i]);
return res;
}
void SA()
{
double cur=calc(),nw,dt;
int x,y;
// int cnt=0;
for(double t=1e5;t>1e-3;t*=0.999) {
// x=rand()%n+1,y=rand()%n+1;
// if((++cnt)%1000==0) cur=calc();
if(suggest==0) suggest=rand()%n+1;
x=((suggest+(int)rnd(-t,t)+(int)rnd(-10,10))%n+n)%n+1;
y=rand()%n+1;
// y=(rand()%2000+x)%n+1;
if(x==y) continue;
nw=cur-add(x,y);
swap(a[x],a[y]);
nw+=add(x,y);
dt=nw-cur;
if(exp(-dt/t)>rnd(0,1)) {
cur=calc();
// cerr<<cur<<endl;
}
else swap(a[x],a[y]);
}
random_shuffle(a+1,a+n+1);
}
int main()
{
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
int i;
srand((unsigned) time(0));
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%lld%lld",&a[i].x,&a[i].y);
LL mn1=INF,mx1=-INF,mn2=INF,mx2=-INF;
for(i=1;i<=n;i++) {
mn1=min(mn1,a[i].x);
mx1=max(mx1,a[i].x);
mn2=min(mn2,a[i].y);
mx2=max(mx2,a[i].y);
}
if(mx2-mn2>=mx1-mn1) {
for(i=1;i<=n;i++)
swap(a[i].x,a[i].y);
}
memcpy(b,a,sizeof b);
sort(a+1,a+n+1);
int hh=1,tt=n;
for(i=1;i<=n;i++) {
if(i&1) c[i]=a[hh++];
else c[i]=a[tt--];
}
// for(i=1;i<=n;i++)
// printf("%lld %lld\n",a[i].x,a[i].y);
memcpy(a,c,sizeof a);
// for(int i=1;i<=10;i++) random_shuffle(a+1,a+n+1);
while(clock()<1.8*CLOCKS_PER_SEC) SA();
// SA();
puts("-1");
return 0;
}
// time 1