vp了一下,居然冲到了rk15,不错,感觉题的质量都不高啊,甚至有很多题数据错了,比如I题,HJL似乎都是错的
牛客竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com)
A伟大奋斗
模拟
#include
//#define int long long
#define low(x) (x&(-x))
using namespace std;
const int mxn=3e2+10;
const int mxe=1e5+10;
const int mod=9901;
int n;
void solve(){
cin>>n;
cout<>__;
while(__--)solve();return 0;
}
B可莉的五子棋
模拟
写了依托
#include
#define int long long
#define low(x) (x&(-x))
using namespace std;
const int mxn=1e3+10;
const int mxe=1e5+10;
const int mod=9901;
int n,m;
string s[mxn];
void solve(){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>s[i],s[i]=" "+s[i];
int ans1=0,ans2=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(i+4<=n){
if(s[i][j]==s[i+1][j]&&s[i+1][j]==s[i+2][j]&&s[i+2][j]==s[i+3][j]&&s[i+3][j]==s[i+4][j]&&s[i][j]=='1') ans1++;
}
if(i+4<=n){
if(s[i][j]==s[i+1][j]&&s[i+1][j]==s[i+2][j]&&s[i+2][j]==s[i+3][j]&&s[i+3][j]==s[i+4][j]&&s[i][j]=='2') ans2++;
}
if(j+4<=m){
if(s[i][j]==s[i][j+1]&&s[i][j]==s[i][j+2]&&s[i][j]==s[i][j+3]&&s[i][j]==s[i][j+4]&&s[i][j]=='1') ans1++;
}
if(j+4<=m){
if(s[i][j]==s[i][j+1]&&s[i][j]==s[i][j+2]&&s[i][j]==s[i][j+3]&&s[i][j]==s[i][j+4]&&s[i][j]=='2') ans2++;
}
if(i+4<=n&&j+4<=m){
if(s[i][j]==s[i+1][j+1]&&s[i][j]==s[i+2][j+2]&&s[i][j]==s[i+3][j+3]&&s[i][j]==s[i+4][j+4]&&s[i][j]=='1') ans1++;
}
if(i+4<=n&&j+4<=m){
if(s[i][j]==s[i+1][j+1]&&s[i][j]==s[i+2][j+2]&&s[i][j]==s[i+3][j+3]&&s[i][j]==s[i+4][j+4]&&s[i][j]=='2') ans2++;
}
if(i-4>=1&&j+4>=1){
if(s[i][j]==s[i-1][j+1]&&s[i][j]==s[i-2][j+2]&&s[i][j]==s[i-3][j+3]&&s[i][j]==s[i-4][j+4]&&s[i][j]=='1') ans1++;
}
if(i-4>=1&&j+4>=1){
if(s[i][j]==s[i-1][j+1]&&s[i][j]==s[i-2][j+2]&&s[i][j]==s[i-3][j+3]&&s[i][j]==s[i-4][j+4]&&s[i][j]=='2') ans2++;
}
}
}
cout<>__;
while(__--)solve();return 0;
}
C消除死域点
树上倍增
思路:
先去预处理出所有结点的sz和dep,标记出哪些结点是死结点,然后考虑去枚举删哪条边,对于考虑删掉的某条边,该边下面的sz都不变,上面的死结点有些就不死了,因此我们需要快速算出上面有几个不死结点。注意到离该边比较近的结点一定会不死,再远的结点一定死了,因此具有二段性,可以在树上二分,而树上倍增其实就相当于在树上二分了,我们倍增地跳上去,直到跳到dep[p]-dep[x]-1>k为止。然后边枚举边维护贡献最大值,最后减去这个最大的贡献就好了
#include
using namespace std;
const int mxn=5e5+10;
const int mxe=5e5+10;
struct ty{
int to,next;
}edge[mxe<<1];
struct Edge{
int u,v;
}e[mxe<<1];
map mp[mxn];
vector V;
int n,k,u,v,tot=0,mx=0;
int head[mxn],sz[mxn],dep[mxn];
int F[mxn][33];
void add(int u,int v){
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}
void init(){
tot=0;
for(int i=0;i<=n;i++) head[i]=-1;
}
void dfs(int u,int fa){
sz[u]=1;dep[u]=dep[fa]+1;
F[u][0]=fa;
for(int i=1;i<=30;i++) F[u][i]=F[F[u][i-1]][i-1];
for(int i=head[u];~i;i=edge[i].next){
if(edge[i].to==fa) continue;
dfs(edge[i].to,u);
sz[u]+=sz[edge[i].to];
}
}
void dfs2(int x,int fa){
//cout<=k){
int p=x;
for(int i=30;i>=0;--i){
if(F[p][i]&&sz[F[p][i]]-sz[x]>n>>k;
init();
for(int i=1;i<=n-1;i++){
cin>>u>>v;
add(u,v);
add(v,u);
//e[i]={u,v};
}
dfs(1,0);
//for(int i=1;i<=n;i++) cout<=k) V.push_back(i);
}
//for(int i=0;idep[e[i].v]&&check(e[i].v,V[j])) res++,cout<=k) ans++;
}
//cout<>__;
while(__--)solve();return 0;
}
D是期望题,不会,单独补QwQ
E病毒危机
模拟
思路:
直接模拟
直接把队友代码贴上来吧
#include
using namespace std;
const int mxn=1e5+10;
int n,m,k,a[mxn],ans=1,v[mxn];
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>m;
cin>>k;
for(int x,i=1;i<=k;i++) cin>>x,v[x]=1;
for(int f,i=2;i<=n;i++){
cin>>k,f=0;
for(int x,i=1;i<=k;i++){
cin>>x;
if(v[x]) f=1;
}
if(f) ans++;
}
cout<
F互质
构造
思路:
因为要和n互质,因此直接构造n-1,又要在范围里,直接输出(n-1)/2即可,然后对6进行特判
#include
using namespace std;
const int mxn=1e6+10;
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
long long t,n,ans;
cin>>t;
while(t--){
cin>>n;
if(n==6) cout<<-1<<'\n';
else cout<<(n-1)/2<<'\n';
}
return 0;
}
G 栈与公约数
暴力
思路:
呃呃,这题写个暴力加个break就能过,逆
#include
using namespace std;
const int mxn=1e6+10;
long long t,op,x,a[mxn],tot,d;
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>t;
while(t--){
cin>>op;
if(op==1) cin>>x,a[++tot]=x;
if(op==2) tot--;
if(op==3) cout<>x;
for(int i=tot;i>=tot-x+1;i--){
d=__gcd(a[i-1],a[i]);
if(d==1) break;
}
for(int i=tot;i>=tot-x+1;i--) a[i]=d;
}
}
return 0;
}
I 图的分割
二分+并查集
思路:
首先有个贪心策略,因为要保证最大边最小,因此考虑从小到大去连边,直到连到了两个连通块
那么注意到这具有二段性,即最大边太小就不止两个,太大就只有一个
因此可以去二分
在check里面,因为删除的最大边是mid,因此把大于mid的边全部连上,去看看是不是有两个连通块
#include
using namespace std;
const int mxn=1e6+10;
const int mxe=1e6+10;
struct ty{
int u,v,w;
}e[mxe<<1];
int n,m,u,v,w,ans,cnt;
int f[mxn];
int find(int x){
return f[x]=(x==f[x])?x:find(f[x]);
}
void join(int u,int v){
int f1=find(u),f2=find(v);
if(f1!=f2) f[f1]=f2;
cnt--;
}
bool check(int mid){
for(int i=1;i<=n;i++) f[i]=i;
cnt=n;
for(int i=1;i<=m;i++){
if(e[i].w>mid) join(e[i].u,e[i].v);
}
return cnt!=1;
}
void solve(){
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>u>>v>>w;
e[i]={u,v,w};
}
int l=1,r=1e8;
while(l<=r){
int mid=l+r>>1;
if(check(mid)){
r=mid-1;
ans=mid;
}else l=mid+1;
}
cout<>__;
while(__--)solve();return 0;
}
这样直接考虑n-2条边的居然也能过,6
#include
using namespace std;
const int mxn=1e6+10;
int n,m,u,v,a[mxn];
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<=m;i++) cin>>u>>v>>a[i];
sort(a+1,a+m+1);
cout<
K 俄罗斯方块
不懂,队友过的,贴一下代码
#include
using namespace std;
int a[1100][1100],e[8][8]={{1},{1,1},{1,7,7},{2,7,7,4},{2,2,3,4,4},{2,3,3,4,9,9},{8,8,3,5,9,9,6},{8,8,5,5,5,6,6,6}};
int ee[7][7]={{1},{1,1},{1,2,2},{3,2,2,4},{3,3,4,4,4},{3,5,6,6,6,7},{5,5,5,6,7,7,7}};
int r[8][8]={{1,1,2,2,3,3,4,4},{1,1,2,2,3,3,4,4},{5,5,6,6,7,7,8,8},{5,5,6,6,7,7,8,8},{9,9,10,10,11,11,12,12},{9,9,10,10,11,11,12,12},{13,13,14,14,15,15,16,16},{13,13,14,14,15,15,16,16}};
int rr[8][7]={{1,2,2,2,3,11,11},{1,1,2,3,3,11,11},{1,4,4,4,3,12,12},{9,9,4,10,10,12,12},{9,9,5,10,10,13,13},{6,5,5,5,8,13,13},{6,6,7,8,8,14,14},{6,7,7,7,8,14,14}};
int main()
{
int n,i,j,k,l,m,h;
cin>>n;
if((n*(n+1)/2)%4){
cout<<"NO";
return 0;
}
cout<<"YES\n";
if(n==7){
for(i=0;i8&&i%8==7){
h+=9+i/8*16;
}
k=(k%8)+1;
cout<
M 画画
构造
纯构造,讨论n的奇偶性,尽量全部填满
#include
using namespace std;
int a[1100][1100];
int main()
{
int t,n,i,j,k,l,m;
cin>>t;
while(t--){
scanf("%d",&n);
memset(a,0,sizeof a);
if(n%2){
for(i=0;i