Day3上
T1
星空
【问题描述】
你是能看到第一题的friends 呢。
——hja
点点星空是一张𝑁 × 𝑀的棋盘,左下角有颗星星。尤和千每次可以将星星向
右边、右上、上边移动一格。尤和千轮流移动,尤先手,问尤是否必胜?
【输入格式】
多组数据,每行两个整数𝑁, 𝑀,当𝑁 = 𝑀 = 0时数据停止。
【输出格式】
对于每组数据,如果尤必胜输出“Yuri”,否则输出“Chito”。
【样例输入】
5 3
5 4
6 6
0 0
【样例输出】
Chito
Yuri
Yuri
【数据范围与规定】
对于50%的数据,1 ≤ 𝑁, 𝑀 ≤ 10。
对于100%的数据,1 ≤ 𝑁, 𝑀 ≤ 1000。
思路:
我是想,用布尔型的dp推ij这种状态,谁必赢。
如果这局1必输,那么 ,f[i+1][j]=f[i][j+1]=f[i+1][j+]=1 必赢
都是奇数,先手必败,否则先手必胜。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<algorithm> #include<queue> #include<cstring> #include<cmath> #include<ctime> using namespace std; const int N=1001; int n,m,tmp; bool f[1010][1010]; void first() { for(int i=1;i<=N;i++) f[i][0]=!f[i-1][0]; for(int j=0;j<=N;j++) for(int i=j;i<=N;i++) if(!f[i][j]) f[i+1][j]=f[i][j+1]=f[i+1][j+1]=1; } int main() { freopen("star.in","r",stdin); freopen("star.out","w",stdout); first(); scanf("%d%d",&n,&m); while(n||m) { tmp=max(n,m); m=min(n,m);n=tmp; m--;n--; if(f[n][m]) printf("Yuri\n"); else printf("Chito\n"); scanf("%d%d",&n,&m); } return 0; }
战争
【问题描述】
你是能看到第二题的 friends呢。
—— laekov
战场上有 𝑁个数,两异或可以得到 𝑁×𝑁−12个数,求这些中前 𝐾大的 数 的和。
【输入格式】
第一行两个 整数 𝑁,𝐾。
接下来一行 𝑁个数 。
【输出格式】
一行个整数代表答案 对109+7取模之后的结果 。
【样例输入】
3 1
1 2 3
【样例输出】
3
【数据范围与规定】
对于 40%的数据 ,𝑁≤100。
对于另外 20%的数据, 𝐾=1。
对于另外 20%的数据,所有不超过 1023。
对于 100%的数据 ,1≤𝑁≤5×104,所有数不超过 ,所有数不超过 ,所有数不超过 231−1且非负 ,𝐾一定 合法 。
有点怵
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<algorithm> #include<queue> #include<cstring> #include<cmath> #include<ctime> using namespace std; const int N=1e4*5+100; const int M=1025; int n,k; int a[N],maxn; bool sum[N]; int main() { freopen("war.in","r",stdin); freopen("war.out","w",stdout); scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&a[i]); if(n<=100) { priority_queue<int>q; for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) q.push(a[i]^a[j]); long long ans=0; for(int i=1;i<=k;i++) { ans+=q.top(); q.pop(); } cout<<ans; return 0; } if(k==1) { int maxn=0; for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) maxn=max(maxn,a[i]^a[j]); cout<<maxn; return 0; } for(int i=1;i<=n;i++) sum[a[i]]=1; for(int i=1;i<=M;i++) if(sum[i]) for(int j=1;j<=n;j++) maxn=max(maxn,a[j]^i); cout<<maxn; return 0; }
:暴力求
:分治从大到小看看每一位能否得到
:放到桶里
正解 二分+tree树
先求第K大,把比他大的加。二分K大数,找有多少个比他大。
无题
【问题描述】
你是能看到第三题的 friends呢。
—— aoao
世界已无名字,而题目仍然存在。
𝑁个数, 𝑀次操作,每询问 区间第 𝑘大,或者给区间加上一个数 。
【输入格式】
第一行 两个整数 𝑁,𝑀。
接下来一行 𝑁个数代表初始值。
接下来 𝑀行,每第一个数 行,每第一个数 行,每第一个数 行,每第一个数 𝑜𝑝𝑡代表操作种类。如果 代表操作种类。如果 代表操作种类。如果 代表操作种类。如果 𝑜𝑝𝑡=0,那么接下来三 ,那么接下来三 ,那么接下来三 个数 𝑙,𝑟,𝑘,代表询问第 ,代表询问第 𝑙到第 𝑟个数中第 𝑘大的是多少;如果 大的是多少;如果 𝑜𝑝𝑡=1,那么接下来 ,那么接下来 三个数 𝑙,𝑟,𝑣,代表给第 𝑙到第 𝑟个数全部加上 𝑣。
【输出格式】
对于每次询问,输出答案 。如果答案不存在,输出 −1。
【样例输入】
5 3
1 2 3 4 5
0 2 3 1
1 2 4
0 2 3 1
【样例输出】
3
6
【数据规模与约定】
对于 30%的数据, 1≤𝑁,𝑀≤1000。
对于另外 20%的数据, 𝑘=1。
对于另外 20%的数据,没有修改操作。//主席树或 离线(莫队+堆)
对于 100%的数据, 1≤𝑁,𝑀≤105,1≤𝐾≤10。
希望有分。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
a#include<iostream> #include<cstdio> #include<algorithm> #include<queue> #include<cstring> #include<cmath> #include<ctime> using namespace std; const int N=1e5+2; int n,m; int a[N]; int d[N]; int main() { freopen("noname.in","r",stdin); freopen("noname.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1,opt,l,r,v;i<=m;i++) { scanf("%d%d%d%d",&opt,&l,&r,&v); if(opt) { d[l]+=v,d[r+1]-=v; }else { if(v==1) { int j,o,tot=0,ans=0; for(j=1;j<=l;j++) tot+=d[j]; for(j=l;j<=r;j++) ans=max(ans,tot+a[j]),tot+=d[j+1]; printf("%d\n",ans); continue; } priority_queue<int>q; int tot=0,o,j; for(j=1;j<=l;j++) tot+=d[j]; for(j=l;j<=r;j++) q.push(a[j]+tot),tot+=d[j+1]; for(j=1;j<v;j++) {o=q.top();q.pop();} o=q.top(); printf("%d\n",o); } } return 0; }
没看到-1
线段树,维护前十大。
如何更新? 合并子树的,前十大,指针移动。
修改? 整个区间的修改,前十大+v。
合并,加法操作,重载运算。
如何返回前十大数,