【Jan.Challenge】总结

本文详细解析了CodeChef月赛中的六道题目,包括A题的递归算法、B题的质数应用、C题的坐标处理技巧、D题的贪心算法、E题的容斥原理以及F题的动态规划方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://www.codechef.com/JAN16?order=desc&sortBy=successful_submissions

这场月赛里除了第四道每题都有磕磕绊绊的感觉。。。展示一下战绩吧:


A.


先做出了4、5的我居然被这题坑了一晚上。。。

递推图画出来很好解释。先把上一层继承下来的东西看作一团雾,然后你发现这一层的新来的数字放开头时刚好和上一层的所有值的开头都乘了一遍(另外还有原来上一层和的数据),哦,然后这团雾就有了定义——上一层的所有值的开头。那么再考虑把这一层的新来的数字放结尾,然后发现和上一层的所有值的结尾都乘了一遍(另外还有原来上一层和的数据)。哦,那么要更新这团雾的定义了——上一层所有值的开头之和+结尾之和。
那么,要怎么计算这一层的和呢?
首先,不考虑所有和这一层新来的值做乘法的运算,那么就会发现,上一层的和在这一层用了两回,所以*2。
又由乘法结合律,即a*b+a*c=a*(b+c),提取公因式(这一层新来的值),剩下的值就是上一层的雾。所以这一层的和=上一层的和*2+这一层新来的值*这团雾。
那么,又怎么计算这团雾?
这就要考你的眼力以及数学归纳法了。假设在第i层,那么第i层的雾就等于上一层的雾+这一层的值*(上一层的个数*2)。这个图画出来还是很好理解的。

ll po[100005];
int main(){
	po[0]=1;
	for(int i=1;i<=100001;++i)
		po[i]=po[i-1]*2%mod;
	int t;
	cin>>t;
	while(t--){
		int n,a;
		cin>>n;
		cin>>a; 
		ll s=0,ss=a;
		for(int i=0;i<n;++i){
			cin>>a;
			s=(s+ss*a%mod)%mod;
			s=s*2%mod;
			ss=(ss+po[i]*a%mod)%mod;
		}
		cout<<s<<endl;
	}
	return 0;
}  

B.


从一开始的完全没思路到后来有思路却发现是错的(..),想把所有数字中出现的因子都提出来再全都去尝试一遍取最小解,显然光因子的个数就会爆炸了。于是转而想到了用素数,YY一发所有的数都必须要凑到被一个素数刚好整除。

const int MAXN = 10000;
unsigned int plist[10000], pcount;
unsigned int isPrime[(MAXN >> 5) + 1];
#define setbitzero(a) (isPrime[(a) >> 5] &= (~(1 << ((a) & 31))))
#define setbitone(a) (isPrime[(a) >> 5] |= (1 << ((a) & 31)))
#define ISPRIME(a) (isPrime[(a) >> 5] & (1 << ((a) & 31)))
void initPrime() {
    int i, j, m;
    int t = (MAXN >> 5) + 1;
    for (i = 0; i < t; ++i) {
        isPrime[i] = 2863311530;
    }
    plist[0] = 2;
    setbitone(2);
    setbitzero(1);
    m = (ll) sqrt((double)MAXN);
    pcount = 1;
    for (i = 3; i <= m; i += 2) {
     if (ISPRIME(i)) {
    plist[pcount++] = i;
     for (j = i << 1; j <= MAXN; j += i) {
    setbitzero(j);
    }
     }
     }
    if (!(i & 1)) {
     ++i;
     }
     for (; i <= MAXN; i += 2) {
     if (ISPRIME(i)) {
     plist[pcount++] = i;
     }
     }
} 
int x[10005];
int main(){
	initPrime();
	int t;
	sd(t);
	while(t--){
		int n;
		sd(n);
		for(int i=0;i<n;++i)
			sd(x[i]);
		int p=0;
		if(x[0]==1)
			x[0]=2,p++;
		for(int i=1;i<n;++i){
			if(x[i]<x[i-1]){
				p+=x[i-1]-x[i];
				x[i]=x[i-1];
			}
		}
		int minn=1000000000;
		for(int i=0;i<pcount;++i){
			int s=0;
			for(int j=0;j<n;++j){
				if(x[j]%plist[i]!=0)
					s+=plist[i]-x[j]%plist[i];
			}
			minn=min(minn,s);
		}
		printf("%d\n",minn+p);
	}
	return 0;
}  

C.


这题也是够坑的,我都用上了凸包(不过超时了),再加上题目意思又搞错(8方向),总之也是脑洞题啊。。。如果不是题目不是格子的话就真该用凸包了。。。

struct Point
{
    int x,y;
};
Point p[1000005];
char x[1005][1005];
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		int nn,m;
		scanf("%d%d",&nn,&m);
		int n=0;
		for(int i=0;i<nn;++i){
			scanf("%s",x[i]);
			int maxx=-10000000,minn=10000000;
			for(int j=0;j<m;++j){
				if(x[i][j]=='*'){
					maxx=max(maxx,j);
					minn=min(minn,j);
				}
			}
			if(maxx==-10000000&&minn==10000000)
				continue;
			else if(maxx==minn)
				p[n].x=i,p[n++].y=maxx;
			else{
				p[n].x=i,p[n++].y=maxx;
				p[n].x=i,p[n++].y=minn;
			}
		}
		for(int i=0;i<m;++i){
			int maxx=-10000000,minn=10000000;
			for(int j=0;j<nn;++j){
				if(x[j][i]=='*'){
					maxx=max(maxx,j);
					minn=min(minn,j);
				}
			}
			if(maxx==-10000000&&minn==10000000)
				continue;
			else if(maxx==minn)
				p[n].x=maxx,p[n++].y=i;
			else{
				p[n].x=maxx,p[n++].y=i;
				p[n].x=minn,p[n++].y=i;
			}
		}
        int maxx=0;
		for(int i=0;i<n;++i){
        	for(int j=i+1;j<n;++j){
        		int w=max(abs(p[i].x-p[j].x),abs(p[i].y-p[j].y));
        		maxx=max(maxx,w/2+w%2);
        	}
        }
        if(n==0)
        	cout<<0<<endl;
        else
        	printf("%d\n",maxx+1);
    }
    return 0;
} 

D.


作为第一道AC的题目,表示很简单(贪心,题目绕了点而已)。。。

ll x[100005],y[200005];
int main(){
	int t;
	cin>>t;
	while(t--){
		int n,k,m;
		cin>>n>>k>>m;
		for(int i=0;i<n;++i)
			cin>>x[i];
		for(int i=0;i<n;++i)
			cin>>y[i];
		for(int i=0;i<n;++i)
			x[i]-=y[i];
		sort(x,x+n);
		for(int i=0;i<m+k;++i)
			cin>>y[i];
		m+=k;
		sort(y,y+m);
		int p=m-1;
		ll s=0;
		for(int i=n-1;i>=0;--i){
			if(p<0)
				s+=x[i];
			else{
				int u=0;
				while(p>=0&&y[p]>x[i]){
					p--;
				}	
				if(p>=0)
					s+=x[i]-y[p];
				else
					s+=x[i];
				p--;
			}
		}
		cout<<s<<endl;
	}
	return 0;
}  

E.


容斥原理。代码太长放pastebin里面了。一开始无从下手,图的话画到5就已经很麻烦的情况了,容斥里面不可能出现的情况是硬靠自己YY出来的。。。

http://paste.ubuntu.com/14582010/

F.


dp。然而我一开始觉得并不能dp(因为复杂度太高了),然而几天后发现是我的切入方式不对。。。我表示在比赛的时候花这么长时间去想是万万不能的。

double x[1005][1005],y[1005][1005],dp[1005][1005][4];
int main(){
	int n,m;
	double k;
	cin>>n>>m>>k;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j){
			cin>>x[i][j]>>y[i][j];
		}
	}
	for(int i=1;i<=n;++i){
		dp[1][i][0]=k/x[i][1];
		dp[1][i][3]=k;
	}
	double maxx=k;
	for(int i=2;i<=m;++i){
		for(int j=1;j<=n;++j){
			dp[i][j][2]=max(dp[i][j][2],dp[i-1][j][0]); //i秒不交易,处于货币状态
			dp[i][j][2]=max(dp[i][j][2],dp[i-1][j][2]);
			dp[i][j][2]=max(dp[i][j][2],dp[i-1][j-1][2]);
			dp[i][j][2]=max(dp[i][j][2],dp[i-1][j-1][0]);
			dp[i][j][2]=max(dp[i][j][2],dp[i-1][j+1][2]);
			dp[i][j][2]=max(dp[i][j][2],dp[i-1][j+1][0]);
			
			dp[i][j][3]=max(dp[i][j][3],dp[i-1][j][1]); //i秒不交易,处于商品状态
			dp[i][j][3]=max(dp[i][j][3],dp[i-1][j][3]);
			dp[i][j][3]=max(dp[i][j][3],dp[i-1][j-1][3]);
			dp[i][j][3]=max(dp[i][j][3],dp[i-1][j-1][1]);
			dp[i][j][3]=max(dp[i][j][3],dp[i-1][j+1][3]);
			dp[i][j][3]=max(dp[i][j][3],dp[i-1][j+1][1]);
			
			dp[i][j][0]=max(dp[i][j][0],dp[i-1][j][0]); //i秒交易,处于货币状态 
			dp[i][j][0]=max(dp[i][j][0],dp[i-1][j][1]/x[j][i]);
			dp[i][j][0]=max(dp[i][j][0],dp[i-1][j][3]/x[j][i]);
	
			dp[i][j][1]=max(dp[i][j][1],dp[i-1][j][1]); //i秒交易,处于商品状态
			dp[i][j][1]=max(dp[i][j][1],dp[i-1][j][0]*y[j][i]);
			dp[i][j][1]=max(dp[i][j][1],dp[i-1][j][2]*y[j][i]);
			
			maxx=max(maxx,dp[i][j][1]);
			maxx=max(maxx,dp[i][j][3]);
			if(maxx>maxxx)
				break;
		}
		if(maxx>maxxx)
			break;
	}
	if(maxx>maxxx)
		cout<<"Quintillionnaire"<<endl;
	else
		printf("%.8f\n",maxx);
    return 0;
}  


内容概要:本文档详细介绍了Analog Devices公司生产的AD8436真均方根-直流(RMS-to-DC)转换器的技术细节及其应用场景。AD8436由三个独立模块构成:轨到轨FET输入放大器、高动态范围均方根计算内核和精密轨到轨输出放大器。该器件不仅体积小巧、功耗低,而且具有广泛的输入电压范围和快速响应特性。文档涵盖了AD8436的工作原理、配置选项、外部组件选择(如电容)、增益调节、单电源供电、电流互感器配置、接地故障检测、三相电源监测等方面的内容。此外,还特别强调了PCB设计注意事项和误差源分析,旨在帮助工程师更好地理解和应用这款高性能的RMS-DC转换器。 适合人群:从事模拟电路设计的专业工程师和技术人员,尤其是那些需要精确测量交流电信号均方根值的应用开发者。 使用场景及目标:①用于工业自动化、医疗设备、电力监控等领域,实现对交流电压或电流的精准测量;②适用于手持式数字万用表及其他便携式仪器仪表,提供高效的单电源解决方案;③在电流互感器配置中,用于检测微小的电流变化,保障电气安全;④应用于三相电力系统监控,优化建立时间和转换精度。 其他说明:为了确保最佳性能,文档推荐使用高质量的电容器件,并给出了详细的PCB布局指导。同时提醒用户关注电介质吸收和泄漏电流等因素对测量准确性的影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值