比赛链接
A.减肥计划
签到题
暴力模拟,如果模拟到最重的人到队首还没有人连续获胜\(k\)轮,那么答案显然就是最重的人。
方便起见可以用双端队列模拟。
时间复杂度\(\Theta(n)\)
代码
点击查看代码
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
#define maxn 1000010
using namespace std;
struct dat{
int val,pos;
dat(){}
dat(int t1,int t2){val=t1,pos=t2;}
} a[maxn];
deque<dat> q;
int cnt[maxn];
int main(){
int i,j,n,k,flag=0,ok=0,p,ans;
scanf("%d%d",&n,&k);
for(i=1;i<=n;++i){
scanf("%d",&a[i].val);
a[i].pos=i;
q.push_back(a[i]);
if(!p||a[i].val>a[p].val) p=i;
}
for(i=1;i<=n;++i){
dat x=q.front();
q.pop_front();
dat y=q.front();
q.pop_front();
if(x.val>=y.val){
cnt[x.pos]++,cnt[y.pos]=0;
q.push_front(x);
q.push_back(y);
}
else{
cnt[y.pos]++,cnt[x.pos]=0;
q.push_front(y);
q.push_back(x);
}
if(cnt[x.pos]>=k){
ans=x.pos;
ok=1;
break;
}
if(cnt[y.pos]>=k){
ans=y.pos;
ok=1;
break;
}
}
if(!ok) ans=p;
printf("%d",ans);
// system("pause");
return 0;
}
C.测量学
签到题
首先如果\(\theta>\pi\),令\(\theta=2\pi-\theta\)
写出路程和\(r\)之间的关系式\(dis=2*(R-r)+theta*r\),发现是关于\(r\)的一次函数。然后就做完了。
代码
点击查看代码
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#define db double
#define maxn 100010
using namespace std;
db r[maxn];
const db pi=acos(-1);
int main(){
int i,j,n,m;
db R,theta,ans;
scanf("%d%lf%lf",&n,&R,&theta);
if(theta>pi) theta=2*pi-theta;
for(i=1;i<=n;++i) scanf("%lf",&r[i]);
sort(r+1,r+n+1);
if(theta>2) ans=2*(R-r[1])+theta*r[1];
else ans=theta*R;
printf("%lf",ans);
// system("pause");
return 0;
}
E. 睡觉
简单题
首先根据\(d\)预处理一下\(a\)数组,得到一个只含\(\pm 1\)的数组\(b\),然后\(d\)就没用了。
判下最简单的情况,如果\(\sum_{i=1}^n b_i<0\),那么显然可以,输出YES。
如果\(\sum_{i=1}^n b_i>0\),倍长数组,模拟过程,如果找到连续的清醒值\(\leq k\)的片段就输出\(YES\),否则输出\(NO\)。
比较麻烦的是\(\sum_{i=1}^n b_i==0\)的情况,假如模拟两轮后未找到连续的清醒值\(\leq k\)的片段,并不一定代表不可行(考虑\(t>>n\)的情况)。
所以特判,只要这两轮中一直满足清醒值\(\leq k\),那么就可行。
代码
点击查看代码
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#define maxn 100010
using namespace std;
int a[maxn],b[maxn];
int solve(){
int i,j,n,k,x,t,d,sum=0,s=0;
scanf("%d%d%d%d%d",&x,&t,&k,&n,&d);
for(i=1;i<=n;++i) scanf("%d",&a[i]);
for(i=1;i<=n;++i) b[i]=a[i]>d?1:-1;
for(i=1;i<=n;++i) sum+=b[i];
if(sum<0) return 1;
for(i=1;i<=2*n;++i){
x+=b[(i-1)%n+1];
if(x<=k) s++;
else s=0;
if(s>=t) return 1;
}
if(sum==0&&x==k){
for(i=1;i<=2*n;++i){
x+=b[(i-1)%n+1];
if(x>k) return 0;
}
return 1;
}
return 0;
}
int main(){
int i,j,n,m,T;
scanf("%d",&T);
while(T--){
if(solve()) printf("YES\n");
else printf("NO\n");
}
// system("pause");
return 0;
}
G. 排队打卡
简单题
按时间顺序处理事件即可
代码
点击查看代码
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define maxm 500010
#define ll long long
using namespace std;
struct event{
int t;
ll x;
bool operator <(const event z) const{
return t<z.t;
}
event(){}
event(int t1){t=t1;}
} a[maxm];
ll p[maxm];
int main(){
int t,m,i,j,anst=0;
ll n,k,sum=0,ans=-1;
scanf("%d%lld",&t,&n);
scanf("%d%lld",&m,&k);
for(i=1;i<=m;++i){
scanf("%d%lld",&a[i].t,&a[i].x);
}
sort(a+1,a+m+1);
int g=upper_bound(a+1,a+m+1,event(t))-a-1;
for(i=1;i<=m;++i){
p[i]=max(p[i-1]-k*(a[i].t-a[i-1].t),0ll)+a[i].x;
}
if(max(p[g]-k*(t-a[g].t),0ll)!=n){
printf("Wrong Record");
return 0;
}
for(i=g+1;i<=m;++i){
ll tmp=p[i]/k+1;
if(tmp<=ans||ans<0) ans=tmp,anst=a[i].t;
}
printf("%d %lld",anst,ans);
// system("pause");
return 0;
}
H. 提瓦特之旅
题出的很好,但《原神》是由米哈游自主研发的一款全新开放世界冒险游戏。游戏发生在一个被称作「提瓦特」的幻想世界,在这里,被神选中的人将被授予「神之眼」,导引元素之力。你将扮演一位名为「旅行者」的神秘角色 在自由的旅行中邂逅性格各异、能力独特的同伴们,和他们一起击败强敌,找回失散的亲人——同时,逐步发掘「原神」的真相。
简单题
无非是带状态的最短路,分层图解决即可(其实并不需要真的把新图建出来)。
代码
点击查看代码
#include<cstdio>
#include<cstdlib>
#include<queue>
#include<algorithm>
#define maxn 501
#define maxm 100010
#define inf 1ll<<56
#define ll long long
using namespace std;
ll dis[maxn][maxn];
int book[maxn][maxn];
int fst[maxn],nxt[maxm<<1],to[maxm<<1],cnt=0;
ll w[maxm<<1],b[maxn];
void add(int x,int y,ll z){
w[++cnt]=z;
to[cnt]=y;
nxt[cnt]=fst[x];
fst[x]=cnt;
}
struct point{
ll d;
int x,y;
bool operator <(const point t) const{
return d>t.d;
}
point(){}
point(ll t1,int t2,int t3){
d=t1,x=t2,y=t3;
}
};
priority_queue<point> q;
int main(){
int i,j,n,m,k,x,y,Q;
ll z,ans;
scanf("%d%d",&n,&m);
for(i=1;i<=n;++i)
for(j=0;j<n;++j)
dis[i][j]=inf;
for(i=1;i<=m;++i){
scanf("%d%d%lld",&x,&y,&z);
add(x,y,z);add(y,x,z);
}
dis[1][0]=0;
q.push(point(0,1,0));
while(!q.empty()){
point p=q.top();
q.pop();
if(p.d!=dis[p.x][p.y]||book[p.x][p.y]) continue;
book[p.x][p.y]=1;
for(i=fst[p.x];i;i=nxt[i]){
if(book[to[i]][p.y+1]) continue;
if(dis[to[i]][p.y+1]>p.d+w[i]){
dis[to[i]][p.y+1]=p.d+w[i];
q.push(point(dis[to[i]][p.y+1],to[i],p.y+1));
}
}
}
scanf("%d",&Q);
for(i=1;i<=Q;++i){
scanf("%d",&x);
for(j=1;j<n;++j){
scanf("%lld",&b[j]);
b[j]+=b[j-1];
}
ans=inf;
for(j=0;j<n;++j) ans=min(ans,dis[x][j]+b[j]);
printf("%lld\n",ans);
}
// system("pause");
return 0;
}
I. 宠物对战
简单题
看到这么多字符串直接想到用trie存,令\(dp[i][0/1]\)表示后缀\(i\)以\(A\)组串/\(B\)组串开头的最小拼接代价,然后一边在trie上匹配一边\(DP\)即可。
时间复杂度其实是\(\theta(len^2)\)的(令\(len=strlen(S)\))。
代码
点击查看代码
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define maxs 5010
#define inf 0x3f3f3f3f
#define maxn 500010
using namespace std;
char s[maxs];
int trie[2][maxn][26],tot[2];
int flag[2][maxn];
int dp[maxs][2];
void insert(int type,int n,char *p){
int x=0,i;
for(i=0;i<n;++i){
int c=(*p)-'a';
if(!trie[type][x][c]) trie[type][x][c]=++tot[type];
x=trie[type][x][c];
p++;
}
flag[type][x]=1;
}
void search(int type,int p,int n){
int x,i;
x=trie[type][0][s[p]-'a'];
for(i=p;i<n;++i){
if(!x) break;
int nxt=(i<n-1)?trie[type][x][s[i+1]-'a']:0;
if(flag[type][x]) dp[p][type]=min(dp[p][type],dp[i+1][type^1]+1);
x=nxt;
}
return;
}
int main(){
int i,j,n,m,L,ans;
char t[maxn];
scanf("%d",&n);
for(i=1;i<=n;++i){
scanf("%s",t);
L=strlen(t);
insert(0,L,t);
}
scanf("%d",&m);
for(i=1;i<=m;++i){
scanf("%s",t);
L=strlen(t);
insert(1,L,t);
}
scanf("%s",s);
L=strlen(s);
for(i=0;i<L;++i) dp[i][0]=dp[i][1]=inf;
for(i=L-1;i>=0;--i){
search(0,i,L);
search(1,i,L);
}
ans=min(dp[0][0],dp[0][1]);
if(ans>=inf) printf("-1");
else printf("%d",ans);
// system("pause");
return 0;
}
K. 区间和
有点难,但是典题,做过类似的题就秒了。
注意到权值总和很小,所以容易想到令\(cnt[i]\)表示权值为\(i\)的区间数量,然后做下前缀和找到\(\geq k\)的位置即可。
问题转化成了计算\(cnt[i]\)。
对\(a\)做前缀和,区间和\([l,r]\)就转化成了\(pre[r]-pre[l-1]\)的两数之差。
选两个数使得差为给定值的方案数,如果把“差”改成“和”,应该很多人会立刻想到生成函数吧。
其实差也是一样的道理,只不过是负指数项。我们统一给它平移一下,相当于乘\(x^k\),最后再给它移回来不就好了?
然后就是上\(FFT\)了。(模数为\(998244353\)的常用NTT会寄,因为\(cnt\)值可能比模数还大qwq)。
代码
点击查看代码
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#define ll long long
#define db double
#define maxn 1000010
using namespace std;
int a[maxn],pos[maxn<<2];
ll cnt[maxn];
const db pi=acos(-1);
struct comp{
db x,y;
comp(){}
comp(db t1,db t2){x=t1,y=t2;}
comp operator +(comp z){
return comp(x+z.x,y+z.y);
}
comp operator -(comp z){
return comp(x-z.x,y-z.y);
}
comp operator *(comp z){
return comp(x*z.x-y*z.y,x*z.y+y*z.x);
}
} w[maxn<<2],A[maxn<<2],B[maxn<<2],C[maxn<<2];
void FFT(comp *L,int n,int lg,int type){
int i,j,k,t,d;
for(i=1;i<n;++i) pos[i]=(pos[i>>1]>>1)|((i&1)<<lg-1);
for(i=0;i<n;++i){
if(i<pos[i]) swap(L[i],L[pos[i]]);
}
db theta=2*pi/n;
comp z=comp(cos(theta*type),sin(theta*type));
w[0]=comp(1,0);
for(i=1;i<n;++i) w[i]=w[i-1]*z;
for(d=1,t=n>>1;d<n;d<<=1,t>>=1){
for(j=0;j<n;j+=(d<<1)){
for(k=0;k<d;++k){
comp tmp=L[j+k+d]*w[t*k];
L[j+k+d]=L[j+k]-tmp;
L[j+k]=L[j+k]+tmp;
}
}
}
}
void multi(comp *L1,comp *L2,comp *res,int n,int lg){
int i,j;
FFT(L1,n<<1,lg+1,1);FFT(L2,n<<1,lg+1,1);
for(i=0;i<(n<<1);++i) res[i]=L1[i]*L2[i];
FFT(res,n<<1,lg+1,-1);
for(i=0;i<(n<<1);++i) res[i].x/=(n<<1);
}
int main(){
int n,i,j,L,m,lg,q,ans;
ll k;
db z=0;
scanf("%d",&n);
A[0]=comp(1,0);
for(i=1;i<=n;++i){
scanf("%d",&a[i]);
a[i]+=a[i-1];
A[a[i]]=A[a[i]]+comp(1,0);
}
L=a[n];
for(i=0;i<=L;++i) B[i]=A[L-i];
for(i=0;i<=L;++i) z+=A[i].x*(A[i].x-1)/2;
for(m=1,lg=0;m<L+1;m<<=1,++lg);
multi(A,B,C,m,lg);
for(i=0;i<=L;++i) cnt[i]=(ll)floor(C[i+L].x+0.5);
cnt[0]=(ll)floor(z+0.5);
for(i=1;i<=L;++i) cnt[i]+=cnt[i-1];
scanf("%d",&q);
for(i=1;i<=q;++i){
scanf("%lld",&k);
ans=lower_bound(cnt,cnt+L+1,k)-cnt;
printf("%d\n",ans);
}
// system("pause");
return 0;
}
剩下的题以后有空再补吧qwq
标签:专场,int,maxn,补题,2022,ans,theta,include,define From: https://www.cnblogs.com/landmine-sweeper/p/16976516.html