曾记否,到中流击水,浪遏飞舟。|

Moyyer_suiy

园龄:2年8个月粉丝:4关注:18

2024/10/22 模拟赛小记

A.日期速算_date

题意:给你一个日期,然后问 k 天之后日期。形式如“20240229”。保证年份在 2000 - 9999 年。

看榜的时候发现挂掉了,有点迷惑。发现思路没什么问题。把 cin,cout 改成 scanf 和 printf 就过了。

。?。什么 oj 特色。

Code
#include<bits/stdc++.h>
using namespace std;
int T;
int n,k;
int y,m,d;
int pd[10010];
int dayy[14]={0,31,28,31,30,31,30,31,31,30,31,30,31};
void init(){
	for(int i=2000;i<=9999;i++){
		if((i%4!=0)||(i%100==0&&i%400!=0)) pd[i]=365;
		else pd[i]=366;
	}
}
void done(int x){
	if(pd[x]==366) dayy[2]=29;
	else dayy[2]=28;
}
void solve(){
	y=n/10000,m=(n-y*10000)/100,d=(n-y*10000-m*100);
	done(y);
	int tot=d;//当前是这一天的第几天
	for(int i=1;i<m;i++){
		tot+=dayy[i];
	}
	int ay=y,am=m;
	if(k>pd[y]-tot){//这一年能过完 
		k-=pd[y]-tot;
		ay++;
		while(k>pd[ay]) k-=pd[ay++];
		am=1;
	}
	else{
		if(k>dayy[am]-d){
			k-=dayy[am]-d;
			am++;
		}
		else{
			cout<<n+k<<endl; 
			return;
		}
	}
	done(ay);
	while(k>dayy[am]) k-=dayy[am++];
	printf("%d",ay);
	if(am<10) cout<<"0";
	printf("%d",am);
	if(k<10) cout<<"0";
	printf("%d\n",k);
}
int main(){
	init();
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&k);
		solve();
	}
	return 0;
}

B.方阵仪仗队_square

同学给我讲了,大概懂了思路吧。但是我不大想写,于是就不写了。

(呃呃,还是在同学的督促下把这个题补了())

我不大能描述这个过程,总之是用树状数组维护的(优点是常数比线段树小),单点修改,区间查询。依稀知道一点这个是个什么很常见的套路,就是把询问都离线下来,按区间右端点升序排序,然后固定了右端点,移动左端点统计答案。但是我真的不很清楚,大概很多 trick 都忘了吧。

Code
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,Q;
int a[N],pos[N];
int p[N],cnt;
struct node{int L,R,ans,id;}q[N];
void init(){
	for(int i=1;i*i<=2*n;i++) p[++cnt]=i*i;
}
bool cmp1(node a,node b){return a.R<b.R;}
bool cmp2(node a,node b){return a.id<b.id;}
int t[N];
int lowbit(int x){
	return x&(-x);
}
void add(int x){
	while(x<=n){
		t[x]++;
		x+=lowbit(x);
	}
}
int query(int x){
	int res=0;
	while(x){
		res+=t[x];
		x-=lowbit(x);
	}
	return res;
}
int main(){
	scanf("%d",&n);
	init();
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		pos[a[i]]=i;
	}
	scanf("%d",&Q);
	for(int i=1;i<=Q;i++){
		scanf("%d%d",&q[i].L,&q[i].R);
		q[i].id=i;
	}
	sort(q+1,q+Q+1,cmp1);
	int now=1,sum=0;
	for(int i=1;i<=n;i++){
		for(int j=cnt;j;j--){
			int t=p[j]-a[i];
			if(t<1) break;
			if(t>n) continue;
			if(pos[t]>=i) continue;
			add(pos[t]),sum++;
		}
		while(now<=Q&&q[now].R==i){
			q[now].ans=sum-query(q[now].L-1);
			now++;
		}
	}
	sort(q+1,q+Q+1,cmp2);
	for(int i=1;i<=Q;i++) printf("%d\n",q[i].ans);
	return 0;
}

C.倍数路径_path

原:P9759 [COCI2022-2023#3] Bomboni

赛时写的爆搜。不太好意思啊部分分的暴力不会写主要是我也没咋仔细想。赛后补了一下暴力,略有一点思维吧。能拿一半分。如果 n = 1 的时候就是朴素 dp 统计,如果是小范围那就以对 H 取模来转移。每次统计这个取模的余数情况即可。

Code
#include<bits/stdc++.h>
#define ll long long 
using namespace std;
const int N=510;
const int mod=998244353;
int n,H;
ll ans;
ll a[N][N],f[N][N];
ll f2[N][N][22];
void dfs(int x,int y,ll k){
	if(x==n&&y==n){
		if(k%H==0) ans=(ans+1)%mod;
		return;
	}
	if(x>n||y>n) return;
	if(a[x+1][y]!=-1) dfs(x+1,y,(k*a[x+1][y])%mod);
	if(a[x][y+1]!=-1) dfs(x,y+1,(k*a[x][y+1])%mod);
}
void solve1(){
	f[1][1]=1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++){
			if(i==1&&j==1) continue;
			if(a[i][j]==-1) continue;
			f[i][j]=(f[i-1][j]+f[i][j-1])%mod;
		}
	ans=f[n][n]%mod;
}
void solve(){
	f2[1][1][a[1][1]%H]=1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(a[i][j]==-1||(i==1&&j==1)) continue;
			for(int k=0;k<H;k++){
				int t=(k*a[i][j])%H;
				f2[i][j][t]=(f2[i][j][t]+f2[i-1][j][k]+f2[i][j-1][k])%mod;
			}
 		}
	}
	ans=f2[n][n][0];
}
int main(){
	scanf("%d%d",&n,&H);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++){
			scanf("%lld",&a[i][j]);
		}
	if(a[1][1]==-1){
		puts("0");
		return 0;
	}
	if(H==1) solve1();
	else if(n<=5) dfs(1,1,a[1][1]);
	else solve();
	cout<<ans;
	return 0;
}

正解的思路和这个就比较像了。

又 T 掉了,不知道什么原因也不大想调了。几乎是对着题解抄了。这两天有点疲倦,毕竟马上 csp 了。

省流:以 gcd 转移。

预处理出来一些 gcd 防 T 掉,统计 K 的各个因数,通过这些因数转移(计算这些数和这个位置的 a[i][j] 的乘积与 K 的公因数,进一步转移)。

Code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=503;
const int mod=998244353;
int n,K;
int a[N][N];
int ys[2010][2010];
ll f[N][N][244];
ll ans;
int gcd(int a,int b){
	if(a<2010&&b<2010&&ys[a][b]) return ys[a][b];
	if(a<b) swap(a,b);
	if(b) return gcd(b,a%b);
	return a;
}
void init(){
	for(int i=1;i<2010;i++)
		for(int j=i+1;j<2010;j++) ys[i][j]=ys[j][i]=gcd(i,j);
}
vector<int> y;
int num[244],cnt;
int main(){
	init();
	scanf("%d%d",&n,&K);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++){
			scanf("%d",&a[i][j]);
			if(a[i][j]==-1) continue;
			a[i][j]=__gcd(a[i][j],K);
		}
	for(int i=1;i<=K;i++){//分解因数
		if(K%i==0){
			y.push_back(i);
			num[i]=cnt++;
		}
	}
	f[1][1][num[a[1][1]]]=1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++){
			if(a[i][j]==-1) continue;
			for(int p=0;p<y.size();p++){
				f[i][j][num[gcd(1ll*y[p]*a[i][j],K)]]=(f[i][j][num[gcd(1ll*y[p]*a[i][j],K)]]+f[i-1][j][p]+f[i][j-1][p])%mod;
			}
		}
	printf("%lld",f[n][n][y.size()-1]); 
} 

D.平行部落_multiverse

原:P8026 [ONTAK2015] Bajtocja

赛时写的朴素暴力,获得了 10pts 的好成绩。

正解是什么,哈希+并查集维护树上启发式合并?不太想学新东西,先鸽一下吧,大概率不会填坑。

本文作者:Moyyer_suiy

本文链接:https://www.cnblogs.com/Moyyer-suiy/p/18493664

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Moyyer_suiy  阅读(6)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起