建议改成:凯爹吊打 std
。
凯爹被卡常了,可恶啊。
基础篇,但成功暴露了基础很薄弱。T4 LCIS 完全没思路。
T1: 90 ( ightarrow) 80
T1:游戏
对自己暴力太自信了,想数据点分治,但显然 (O(10!cdot 10)) 显然是跑不过 500ms
的 = =。
其实也不好意思说是挂分,因为是乱搞的水了很多分。对拍大概每 3000,4000 组就挂了,但是数据太水,就很偷税
正解是和之前的哪一天她能重回我身边类似,但没有疾患鼠的情况所以更简单。同样两个值连边,统计联通块大小。以上口胡的
正解是并查集。一个装备的两个属性连到并查集里,如果并查集构成了一个环,那么这个并查集是可以都选的。如果并查集构成了一棵树,那么这个并查集除了最大的数都可以选。
从一开始循环选就好了,当选不了了就 break
。(%%% HISKrrr)
Code
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int n,ans;
inline int read(){
int x=0;bool fopt=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')fopt=0;
for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-48;
return fopt?x:-x;
}
int fa[maxn],siz[maxn];
bool flag[maxn];//判断是否为环
int Find(int x){
return x==fa[x]?x:(fa[x]=Find(fa[x]));
}
int main(){
#ifndef LOCAL
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
#endif
n=read();
for(int i=1;i<=10000;i++){
fa[i]=i;
siz[i]=1;
}
for(int i=1;i<=n;i++){
int x=read(),y=read();
int fax=Find(x),fay=Find(y);
if(fax==fay){
flag[fax]=1;
}else{
fa[fax]=fay;
siz[fay]+=siz[fax];
flag[fay]|=flag[fax];
}
}
for(int i=1;i<=10000;i++){
int fai=Find(i);
if((flag[fai]&&siz[fai]>0)||siz[fai]>1){
ans++;siz[fai]--;
}else break;
}
printf("%d
",ans);
return 0;
}
T2:嘟嘟噜
约瑟夫问题,但显然线性是过不去的。
打表发现(建议 (m) 取 (4),很容易找到规律),只有过了一段区间之后才会出现取模的情况,那就是目前的值比下标大的时候。那么我们显然可以计算出下次跳到需要取模的位置,中间直接乘法加上。
设下一次需要跳 (x) 步,目前的值是 (a),那么可以得到:
首先注意一定是小于,因为正好相等的时候是不能取模的,因为实际上正好相等的时候对应到 (0) ~ (n-1) 的编号是比下标小的。
简单移项改等号解得:
那么下次的下标就是 (i+x)。相等的时候需要特判一下,懂的都懂。
最后剩下的部分直接加上就好了。小于 (m) 的部分直接暴力。
时间复杂度 (O(能过))。
当然前提是你要会线性解决约瑟夫问题的式子,可以看前几天的那道题。
UPD:现在我发现在一开始如果不 (+1) 的话就不用特判了 orz
Code
#include <bits/stdc++.h>
using namespace std;
inline int read(){
int x=0;bool fopt=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')fopt=0;
for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-48;
return fopt?x:-x;
}
int main(){
#ifndef LOCAL
freopen("mayuri.in","r",stdin);
freopen("mayuri.out","w",stdout);
#endif
int T=read();
while(T--){
int n=read(),m=read(),x=0,i=m;
for(register int j=2;j<=min(n,m);j++){
x=(x+m)%j;
}
if(n<=m)printf("%d
",x+1);
else{
x+=1;//记得+1!
while(1){
int nxt=i+(int)ceil(1.0*(i-x)/(m-1));
if(nxt>n)break;
x=(x+(nxt-i)*m);
if(x==nxt){
if(++nxt>n)break;
x=(x+m)%nxt;
}else x%=nxt;
i=nxt;
}
x+=(n-i)*m;
printf("%d
",x);
}
}
return 0;
}
T3:天才绅士少女助手克里斯蒂娜
好像直接改改式子,就能用线段树单点修改区间求和了。但是 T2 调了太久,所以本题 10 min 走人 = =。
直接开线段树维护 (x^2)、(y^2)、(xy) 即可。
不开 long long
见祖宗
Code
#include <bits/stdc++.h>
using namespace std;
int n,m;
long long X2,Y2,XY;
const int Mod=20170927;
const int maxn=1e6+10;
inline int read(){
int x=0;bool fopt=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')fopt=0;
for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-48;
return fopt?x:-x;
}
struct Node{
long long x,y;
}v[maxn];
#define lson (rt<<1)
#define rson (rt<<1|1)
struct SEG{
long long x2,y2,xy;
}tree[maxn<<2];
inline void pushup(int rt){
tree[rt].x2=(tree[lson].x2+tree[rson].x2)%Mod;
tree[rt].y2=(tree[lson].y2+tree[rson].y2)%Mod;
tree[rt].xy=(tree[lson].xy+tree[rson].xy)%Mod;
}
void build(int rt,int l,int r){
if(l==r){
tree[rt].x2=(v[l].x*v[l].x)%Mod;
tree[rt].y2=(v[l].y*v[l].y)%Mod;
tree[rt].xy=(v[l].x*v[l].y)%Mod;
return;
}
int mid=(l+r)>>1;
build(lson,l,mid);build(rson,mid+1,r);
pushup(rt);
}
void modify(int rt,int l,int r,int p,long long x,long long y){//这的x和y也要开long long!
if(l==r){
tree[rt].x2=(x*x)%Mod;
tree[rt].y2=(y*y)%Mod;
tree[rt].xy=(x*y)%Mod;
return;
}
int mid=(l+r)>>1;
if(p<=mid)modify(lson,l,mid,p,x,y);
else modify(rson,mid+1,r,p,x,y);
pushup(rt);
}
void query(int rt,int l,int r,int s,int t){
if(s<=l&&r<=t){
X2=(X2+tree[rt].x2)%Mod;
Y2=(Y2+tree[rt].y2)%Mod;
XY=(XY+tree[rt].xy)%Mod;
return;
}
int mid=(l+r)>>1;
if(s<=mid)query(lson,l,mid,s,t);
if(t>mid)query(rson,mid+1,r,s,t);
}
int main(){
#ifndef LOCAL
freopen("kurisu.in","r",stdin);
freopen("kurisu.out","w",stdout);
#endif
n=read();m=read();
for(int i=1;i<=n;i++){
v[i].x=read();v[i].y=read();
}
build(1,1,n);
while(m--){
int opt=read();
if(opt==1){
int p=read(),x=read(),y=read();
modify(1,1,n,p,x,y);
}else{
int l=read(),r=read();
X2=Y2=XY=0;
query(1,1,n,l,r);
printf("%lld
",((X2*Y2%Mod-(XY*XY)%Mod)%Mod+Mod)%Mod);
}
}
return 0;
}
T4:凤凰院凶真
LCIS 并输出方案,爷不会(wtcl)。
奉上金牌教练老姚版 LCIS:
Code
#include <bits/stdc++.h>
using namespace std;
const int maxn=5e3+10;
int n,m;
int a[maxn],b[maxn];
int f[maxn][maxn],pre[maxn][maxn];
inline int read(){
int x=0;bool fopt=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')fopt=0;
for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-48;
return fopt?x:-x;
}
void Print(int x,int y){
if(!x)return;
Print(x-1,pre[x][y]);
if(f[x][y]!=f[x-1][pre[x][y]])
printf("%d ",b[y]);
}
int main(){
#ifndef LOCAL
freopen("phoenix.in","r",stdin);
freopen("phoenix.out","w",stdout);
#endif
n=read();
for(int i=1;i<=n;i++)
a[i]=read();
m=read();
for(int i=1;i<=m;i++)
b[i]=read();
for(int i=1;i<=n;i++){
int Max=0,k=0;
for(int j=1;j<=m;j++){
f[i][j]=f[i-1][j];pre[i][j]=j;
if(a[i]>b[j]&&Max<f[i-1][j]){
Max=f[i-1][j];k=j;
}
if(a[i]==b[j]){
f[i][j]=Max+1;pre[i][j]=k;
}
}
}
int now=0;
for(int i=1;i<=m;i++)
if(f[n][i]>f[n][now])now=i;
printf("%d
",f[n][now]);
Print(n,now);
puts("");
return 0;
}