暑期第6-8周解题报告5篇(8月16日-9月5日)

暑期第6-8周解题报告5篇(8月16日-9月5日)

/**
题目:
杭电2021-8-28
2021中国大学生程序设计竞赛(CCPC)- 网络选拔赛
1007 Function

题意:
给你一个函数f(x)=Ax^2g(x)+Bx^2+Cxg^2(x)+Dxg(x)
其中g(x)代表x的每个位数和,比如g(123)代表1+2+3=6
给你A,B,C,D,N,让你求1到N最小的函数值

思路:
f(x)=Ax^2g(x)+Bx^2+Cxg^2(x)+Dxg(x)
=(Ag(x)+B)x^2+(Cg^2(x)+Dg(x))x
n属于1-1e6,也就是1-1000000
对于g(x),g(x)最大时取x=999999,则g(x)属于1-54
对于每个g(x)相同的数字,是一个二次函数
可以利用对称轴和左右端点来求出最小值 
**/
#include<iostream>
#include<vector>
#include<algorithm>
#define int long long
typedef long long ll; 
using namespace std;
vector<int>v[60];
int a,b,c,d,n;
int calg(int x){
	int ans=0;
	while(x){
		ans=ans+x%10;
		x=x/10;
	}
	return ans;
} 
int calc(int x){
	int g=calg(x);
	return (a*g+b)*x*x+(c*g*g+d*g)*x;
}
void init(){
	for(int i=1;i<=1000000;i++){
		v[calg(i)].push_back(i);
	}
}
signed main(){
	init();
	int t;
	cin >> t;
	while(t--){
		cin  >> a >> b >> c >> d >> n;
		int ans=0x3f3f3f3f;
		for(int i=1;i<=54;i++){//g(x) 
			int A=a*i+b;
			int B=c*i*i+d*i;
        	if(A==0) continue;
        	int dcz=(-B)/(2*A);
        	if(dcz<=1) continue;
            int temp=upper_bound(v[i].begin(),v[i].end(),dcz)-v[i].begin();//对称轴位置
            int bound=upper_bound(v[i].begin(),v[i].end(),n)-v[i].begin();//边界不能超过n
            if(temp<bound&&temp>=1&&v[i][temp]<=n){
            	ans=min(calc(v[i][temp]),ans);	
			}
            if(temp-1<bound&&temp-1>=0&&v[i][temp-1]<=n){
            	ans=min(calc(v[i][temp-1]),ans);
			}
        }
        for(int i=1;i<=54;i++){
            int x1=v[i][0];
            if(x1>n) break;
            int x2=v[i][upper_bound(v[i].begin(),v[i].end(),n)-v[i].begin()-1];//找到第一个小于等于n的数字
            ans=min(calc(x1),ans);
            ans=min(calc(x2),ans);
		} 	
		cout << ans << endl;	
	}
}
/**
题目:
杭电2021-8-28
2021中国大学生程序设计竞赛(CCPC)- 网络选拔赛
1006 Power Sum

题意:
在1^2 2^2 3^2 4^2 5^2...前面加上系数1或者-1,使得结果等于n
式子的长度规定在1~n+2

思路:
构造 
x^2-(x+1)^2-(x+2)^2+(x+3)^2=4
所以只要是四个连续的数字为1001时,结果即为4
可以以4个数数为单位,如果n是4的倍数,那么一直是1001循环下去就好了
否则的话,求出n除以4的余数,将余数用前面的数字解决掉
剩下的就是循环的1001
那么如何解决余数?
可以知道1^2=1,余数为1时,在最前面加上1即可,此时总的答案长度为4*k+1
-1^2-2^2-3^2+4^2=2,余数为2时,在最前面加上0001即可,此时总的长度为4*k+4
-1^2+2^2=3,余数为3时,在最前面加上01即可,此时总的长度为4*k+2
余数是0时,前面无需加任何数字,直接循环,此时总的长度为4*k 
要用字符串输出而不是int一个一个输出 
**/
#include<iostream>
using namespace std;
int main()
{
    int t;
    cin >> t;
    while(t--){
        int n;
        cin >> n;
        int k=n/4;
        int x=n%4;
        if(x==1) cout << 4*k+1 << endl << "1"; 
        else if(x==2) cout << 4*k+4 << endl << "0001"; 
        else if(x==3) cout << 4*k+2 << endl << "01";
        else cout << 4*k << endl;
        while(k--){
            cout << "1001";
        }
        cout << endl;
    } 
    return 0;
 } 
/**
题目:
codeforces2021-8-24
Codeforces Round #740 (Div. 2, based on VK Cup 2021 - Final (Engine))
C Deep Down Below

题意:
有n个洞穴,每个洞穴中有一定的怪物,每个怪物具有一定的护甲值
玩家可以选择一定的顺序进入洞穴,一旦进入以后,只有打败此洞内所有的怪物才可以出来
每次击败一个怪物,玩家的攻击力增加一
问初始攻击力最小多少能够保证玩家击败所有的怪物

思路:
第i个怪有ai的血量,打败需要ai+1的攻击力
打这个怪之前能够提升的攻击力是i-1
所以进洞的时候至少需要ai+1-(i-1)=ai-i+2的攻击力 
按照需要的攻击力从小到大的顺序进洞,这样在打怪的同时还能够提升攻击力
每次进洞的时候,判断当前的攻击力是否满足进洞的条件
如果不满足的话,则将初始的攻击力增加差值
如果满足的话,则计算出洞后的攻击力是多少 
**/
#include<iostream>
#include<algorithm>
#define int long long
typedef long long ll; 
using namespace std;
const int N=1e5+5;
struct node{
	int num;
	int ma;
}a[N];
bool cmp(node a,node b){
	if(a.ma==b.ma){
		return a.num>b.num;
	}
	return a.ma<b.ma;
}
signed main()
{
	int t;
	cin >> t;
	while(t--){
		int n;
		cin >> n;
		for(int i=1;i<=n;i++){
			int x;cin >> x;
			int maxx=0;
			a[i].num=x; 
			for(int j=1;j<=x;j++){
				int m;cin >> m;
				maxx=max(maxx,m-j+2);
			}
			a[i].ma=maxx;
		}
		sort(a+1,a+1+n,cmp);
		int res=0;
		int now=0;
		for(int i=1;i<=n;i++){
			if(now>=a[i].ma){
				now=now+a[i].num;
			}
			else{
				res=res+a[i].ma-now;
				now=a[i].ma+a[i].num;
			}
//			cout << res << " " << now << endl;
		}
		cout << res << endl;
	}
	return 0;
}
/**
题目:
codeforces2021-8-24
Codeforces Round #740 (Div. 2, based on VK Cup 2021 - Final (Engine))
D1 Up the Strip (simplified version)

题意:
有编号为1-n格子的的纸带,初始在n号
现在有两种操作
1.选择一个1~x-1中的整数y,从x移动到x-y
2.选择一个2~x中的整数z,从x移动到x/z向下取整
求从n到1的方案数

思路:
dp[i]=j从1~i-1dp[j]+j从2~idp[i/j]
对于后半部分,可以用整除分块
每一个分块的范围是l~i/(i/l)
**/
#include<iostream>
#define int long long
typedef long long ll; 
using namespace std;
const int N=2e5+5;
int dp[N];
signed main()
{
	int n,mod;
	cin >> n >> mod;
	dp[1]=1;
	int sum=dp[1];
	for(int i=2;i<=n;i++){
		dp[i]=(dp[i]%mod+sum%mod)%mod;
		for(int l=2,r=0;l<=i;l=r+1){
			r=i/(i/l);
			dp[i]=(dp[i]%mod+dp[i/l]*(r-l+1)%mod)%mod;
		}
		sum=(sum%mod+dp[i]%mod)%mod;
	}
	cout << dp[n] << endl;
	return 0;
}
/**
题目:
acwing提高
1118分成互质组

题意:
给定n个正整数,将它们分组,使得每组中任意两个数互质
至少要分成多少个组?

思路:
dfs
对每一个位置有两种操作:
1.对已有的每一个组进行枚举,看能否放入其中.
2.新建一个组,放入其中.
**/
#include<iostream>
#include<algorithm>
using namespace std;
const int N=15;
int n;
int a[N];
int group[N][N];
int vis[N];
int ans;
int flag;
bool check(int group[],int gc,int i){
    for(int j=0;j<gc;j++){
        if(__gcd(a[group[j]],a[i])>1){
            return 0;
        }
    }
    return 1;
}
void dfs(int g,int gc,int x,int st){
    if(g>=ans){
        return;
    }
    if(x==n){
        ans=g;
    }
    flag=1;
    for(int i=st;i<n;i++){
        if(!vis[i] && check(group[g],gc,i)){
            vis[i]=1;
            group[g][gc]=i;
            dfs(g,gc+1,x+1,i+1);
            vis[i]=0;
            flag=0;
        }
    }
    if(flag){
        dfs(g+1,0,x,0);
    }
} 
int main()
{
    cin >> n;
    for(int i=0;i<n;i++){
        cin >> a[i];
    }
    ans=n;//最坏情况下每个数单独一组 
    dfs(1,0,0,0);//第一组,组内0个元素,当前搜第0个元素,从当前组第0个元素开始搜 
    cout << ans << endl;
    return 0;
 } 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值