8 月 15 日做题日记

八月 15 日刷题日记

早上的 CF:

CF1547F Array Stabilization (GCD version)

一天一道思维题。

其实结论猜到了大半,但是没想到倍增优化,去看了一眼 CF 官方题解。

下标这样安排是为了首尾相接,首先看懂这个。

设操作次数是 \(k\),手摸样例我们知道:

  • \(i+k \le n\) 时, \(a_i=\gcd\{a_i,a_{i+1},…,a_{i+k}\}\)

  • \(i+k \ge n\) 时,\(a_i=\gcd(\{a_i,…,a_{n} \},\{a_1,…,a_{i+mid-n}\})\)

一个非常 naive 的就是 ST 表处理区间 \(\gcd\),ST 表对有重复无影响的操作有着妙用。

再者是这个 \(k\) 具有单调性,很显然的是 \(k\) 如果满足条件,那么 \(k+1\) 必满足条件。

复杂度 ST \(\mathcal{O(n\log n)}\),二分加个 \(\log\),判断 \(O(n)\),总体大概 \(\mathcal{O(n \log_{2} n)}\),常数比那些写线段树的小多了。

码。

瞎凑的模拟赛

Link

全都是随机跳题。

P7411 [USACO21FEB] Comfortable Cows S

题目的暗示很明显就是递推。

对于每个新加进去的点 dfs 修改即可。

// Author: Gym_nastics
// Date: 2022-8-15
// Powered by VS Code

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
//#define int long long

const int Mod=1e9+7;
const int N=1e6+7,M=4e3+1;

using namespace std;

inline int read() {
    int x=0,f=0;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) f|=(ch=='-');
    for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
    return f?-x:x;
}

void print(int x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) print(x/10);
    putchar(x%10+'0');
}

int n,ans;
int mp[M][M];
const int dx[]={0,1,-1,0,0};
const int dy[]={0,0,0,1,-1};

inline void dfs(int x, int y) {
	if(!mp[x][y]) return ;
	int res = 0;
	pair<int,int> rest;
	for(int k=1;k<=4;k++) {
		int nx = x + dx[k], ny = y + dy[k];
		if(mp[nx][ny]) res ++; 
		else rest = make_pair(nx,ny); 
	}
	if(res != 3) return;
	mp[x = rest.first][y = rest.second] = 1;
	ans ++;
	for(int k=0;k<=4;k++) {
		int nx = x + dx[k], ny = y + dy[k];
		dfs(nx, ny);
	}
}

signed main() {
    n=read();
    for(int i=1;i<=n;i++){
        int x=read()+1001,y=read()+1001;
        if(mp[x][y]) ans--;
        mp[x][y]=1;
        for(int k=0;k<=4;k++) dfs(x+dx[k],y+dy[k]);
        printf("%d\n",ans);
    }
    return 0;
}

P7687 [CEOI2005] Critical Network Lines

一坨题目其实就是让我们找割边,啥割边满足题意?

因为俩都无了才算数,所以要么联通块一边啥也有,要么一边啥也没有。

然后就做完了。

// Problem: P7687 [CEOI2005] Critical Network Lines
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P7687
// Memory Limit: 64 MB
// Time Limit: 3000 ms
// Author: Gym_nastics
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define debug cout<<"Szt ak ioi\n";
//#define int long long

const int Mod=1e9+7;
const int N=1e6+7,M=2e3+1;

using namespace std;

inline int read() {
    int x=0,f=0;
    char ch=getchar();
    while(!isdigit(ch))f|=(ch=='-'),ch=getchar();
    while(isdigit(ch))x=(x<<1)+(x<<3)+(ch&15),ch=getchar();
    return f?-x:x;
}

vector<int>G[N];
int n,m,dfn[N],low[N],idx;
int a[N],b[N],k,l;
vector<pair<int,int> >A;

void tarjan(int u,int fa){
	dfn[u]=low[u]=++idx;
	for(auto &v:G[u]){
		if(!dfn[v]){
			tarjan(v,u);
			low[u]=min(low[u],low[v]);
			if(low[v]>dfn[u]){
				if(!a[v]||!b[v]||a[v]==k||b[v]==l) 
					A.push_back(make_pair(u,v));
			} 
			a[u]+=a[v],b[u]+=b[v];
		}if(v!=fa) low[u]=min(low[u],dfn[v]);
	}
}

signed main() {
	n=read();m=read();k=read(),l=read();
	for(int i=1;i<=k;i++) a[read()]=1;
	for(int i=1;i<=l;i++) b[read()]=1;
	for(int i=1;i<=m;i++){
		int u=read(),v=read();
		G[u].push_back(v);
		G[v].push_back(u);
	}
	tarjan(1,0);
	printf("%d\n",A.size());
	// sort(A.begin(),A.end());
	for(auto &I:A) printf("%d %d\n",I.first,I.second);
    return 0;
}

剩下俩暴力不想打。

T3 正解是个 SA,T4 正解是个左偏树?@Lxyiiiiii

下午的 NOIp 计划

P3694 邦邦的大合唱站队

状压 DP。但是我不会……

Link

// Problem: P3694 邦邦的大合唱站队
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3694
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Author: Gym_nastics
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define debug cout<<"Szt ak ioi\n";
//#define int long long

const int Mod=1e9+7;
const int N=1e5+7,M=2e3+1;

using namespace std;

inline int read() {
    int x=0,f=0;
    char ch=getchar();
    while(!isdigit(ch))f|=(ch=='-'),ch=getchar();
    while(isdigit(ch))x=(x<<1)+(x<<3)+(ch&15),ch=getchar();
    return f?-x:x;
}

int n,m;
int f[1<<20],s[1<<20],sum[N][21];

signed main() {
	n=read(),m=read();
	for(int i=1;i<=n;i++){
		int a=read();
		for(int j=1;j<=m;j++) sum[i][j]=sum[i-1][j];
		++sum[i][a];
	}
	for(int i=0;i<(1<<m);i++){
		int a=i,cnt=0;
		while(a){
			++cnt;
			if(a&1) s[i]+=sum[n][cnt];
			a>>=1;
		}
		f[i]=INF;
	}f[0]=0;
    for(int i=0;i<(1<<m);i++){
    	for(int j=1;j<=m;j++){
    		if((i>>(j-1)&1)){
    			int l=s[i^(1<<(j-1))],r=s[i];
    			f[i]=min(f[i],f[i^(1<<(j-1))]+sum[n][j]-(sum[r][j]-sum[l][j]));
    		}
    	}
    }
    return 0%printf("%d\n",f[(1<<m)-1]);
}

CF11D A Simple Task

状压。

\(f[i][j]\) 为当前点为 \(i\),状态为 \(j\) 时方案数。

并且强制令第一个经过的点为最小点,以后加入的点不能比它小,这个可以用 lowbit 来求。然后如果枚举点和起点重了,说明找到环,因为是无向图,所以相邻两点之间也算了一遍,相减除二就是答案。

// Problem: CF11D A Simple Task
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF11D
// Memory Limit: 250 MB
// Time Limit: 2000 ms
// Author: Gym_nastics
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define debug cout<<"Szt ak ioi\n";
#define int long long

const int Mod=1e9+7;
const int N=1e6+7,M=2e3+1;

using namespace std;

inline int read() {
    int x=0,f=0;
    char ch=getchar();
    while(!isdigit(ch))f|=(ch=='-'),ch=getchar();
    while(isdigit(ch))x=(x<<1)+(x<<3)+(ch&15),ch=getchar();
    return f?-x:x;
}

#define lowbit(x) (x&-x)
int n,m,f[20][1<<20],Ans;
vector<int>G[20];

signed main() {
	n=read(),m=read();
	for(int i=1;i<=m;i++){
		int u=read()-1,v=read()-1;
		G[u].push_back(v);
		G[v].push_back(u);
	}
	for(int i=0;i<n;i++) f[i][1<<i]=1;
	for(int i=0;i<(1<<n);i++){
		for(int j=0;j<n;j++){
			if(!f[j][i]) continue;
			for(auto &v:G[j]){
				if(lowbit(i)>(1<<v)) continue;
				if(i&(1<<v)){if(lowbit(i)==(1<<v)) Ans+=f[j][i];}
				else f[v][i|(1<<v)]+=f[j][i];
			}
		}
	}
    return 0&printf("%lld\n",(Ans-m)>>1);
}

CF222E Decoding Genome

因为 scanf 调了大半个小时((( 警钟长鸣。

一个没什么难度的 dp + 矩阵快速幂,设 \(f[i][j]\) 为前 \(i\) 位最后一个字符为 \(j\) 的方案数,显然的转移:

\[f[i][j]=\sum_{j=1}^{m} f{[i-1][j]} \times ck[j][k] \]

ck 是判断合法不合法,然后这是个矩阵乘法的形式,直接矩阵快速幂:

\[f_1 \times ck^{n-1} \]

即为最终答案,统计 \(f[1][n]\) 就行了。

// Problem: CF222E Decoding Genome
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF222E
// Memory Limit: 250 MB
// Time Limit: 2000 ms
// Author: Gym_nastics
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define debug cout<<"Szt ak ioi\n";
#define int long long

const int Mod=1e9+7;
const int N=1e6+7,M=2e3+1;

using namespace std;

inline int read() {
    int x=0,f=0;
    char ch=getchar();
    while(!isdigit(ch))f|=(ch=='-'),ch=getchar();
    while(isdigit(ch))x=(x<<1)+(x<<3)+(ch&15),ch=getchar();
    return f?-x:x;
}

int n,m,k;
struct mx{
	int x[61][61];
	mx(){memset(x,0,sizeof x);}
}A,B;

mx operator *(mx a,mx b){
	mx res;
	for(int i=1;i<=60;i++)
	for(int k=1;k<=60;k++)
	for(int j=1;j<=60;j++)
	res.x[i][j]=(res.x[i][j]+a.x[i][k]*b.x[k][j])%Mod;
	return res;
}

mx Pow(mx a,int b){
	mx res;
	for(int i=0;i<=60;i++) res.x[i][i]=1;
	while(b){
		if(b&1) res=res*a;
		b>>=1;a=a*a;
	}
	return res;
}

int jb(char ch){
	if(ch>='a'&&ch<='z') return ch-96;
	return ch-38;
}

signed main() {
	n=read(),m=read(),k=read();
	for(int i=1;i<=m;i++)
	for(int j=1;j<=m;j++)
	A.x[i][j]=1;
	for(int i=1;i<=k;i++){
		char a,b;
		cin>>a>>b;
		A.x[jb(b)][jb(a)]=0;
	}
	for(int i=1;i<=60;i++) B.x[1][i]=1;
	A=Pow(A,n-1);B=B*A;
	int Ans=0;
	for(int i=1;i<=m;i++) Ans+=B.x[1][i],Ans%=Mod;
    return 0&printf("%lld\n",Ans);
}

晚上

浅做一手 ATcoder 的 DP contest 练一下。

水题就不发了,发一下有思考的题目。

AT4526 Knapsack 2

乍一看 01 背包,一看 W 的范围,玩你妈。

然后注意的是极小的 \(n\)\(v_i\),那可不可以这么设背包?

\(f[j]\) 为价值为 \(j\) 时最小的体积,然后就没了…

// Problem: AT4526 Knapsack 2
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/AT4526
// Memory Limit: 1000 MB
// Time Limit: 2000 ms
// Author: Gym_nastics
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define debug cout<<"Szt ak ioi\n";
#define int long long

const int Mod=1e9+7;
const int N=1e6+7,M=2e3+1;

using namespace std;

inline int read() {
    int x=0,f=0;
    char ch=getchar();
    while(!isdigit(ch))f|=(ch=='-'),ch=getchar();
    while(isdigit(ch))x=(x<<1)+(x<<3)+(ch&15),ch=getchar();
    return f?-x:x;
}

int n,W,v[N],w[N],f[N],_;

signed main() {
	n=read(),W=read();_=n*1000;
	for(int i=1;i<=n;i++) w[i]=read(),v[i]=read();
	memset(f,INF,sizeof f);
	f[0]=0;
	for(int i=1;i<=n;i++){
		for(int j=_;j>=v[i];j--)
		f[j]=min(f[j],f[j-v[i]]+w[i]);
	}
	for(int i=_;i;i--)
	if(f[i]<=W) return printf("%d\n",i),0;
	return 0;
}

总结

做了 14 道题,有67道AT的 Ed DP Contest ……

晚上帮一位初一OIer了个题。

总的来说还不错。

posted @ 2022-08-15 22:07  Gym_nastics  阅读(31)  评论(0编辑  收藏  举报