2021 ICPC 江西省大学生程序设计竞赛(正式赛)

K、Many Littles Make a Mickle(签到题)

题目大意:有T组测试样例,每一组测试样例给一个n,一个m,从1-n层,第i层有i*i个房间,每个房间居住m个人,问一共能住多少人?

#include<bits/stdc++.h>
using namespace std;
void solve()
{
	int n,m;
	cin>>n>>m;
	long long ans=0;
	for(int i=1;i<=n;i++)
	{
		ans+=i*i; 
	}
	ans*=m;
	cout<<ans<<endl; 
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	solve();
	return 0;
}

B、Continued Fraction

 

题目大意:有n组测试样例,每一组测试样例包括两个整数x,y。 输出一个n以及n个数a0-an满足题目所给的式子。

 不难看出2=105/38,而红圈内的部分为(105%38)/38的倒数,设当前分子为x,分母为y,那么红圈内部分的分母又转化为求(x%y)/y,递归直到x为1即可。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int ans[N];
void solve()
{
	int a,b;
	int cnt=0;
	cin>>a>>b;
	while(1)
	{
		ans[cnt++]=a/b;//cnt存下一共有几个数 
		int temp;
		temp=b;
		b=a%b;
		a=temp;
		if(a==1)
		break;
	}
	cout<<cnt-1<<" ";
	for(int i=0;i<cnt;i++)
	cout<<ans[i]<<" ";
	cout<<endl; 
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		solve();
	} 
	return 00;
}

L、It Rains Again

 题目大意:有n个挡雨板,每个挡雨板的坐标点为x1,y1,x2,y2.即(x1,y1)与(x2,y2)的连线。问这n个挡雨板能挡住x轴多少长度。

 不难看出,挡了多少雨和y轴没有关系,按照每块板的左x端点排序,累加长度并且去重即可。

 每遍历完一个挡雨板,更新板子最靠后的末端last,每遍历到一个板,先加上x2-x1即该挡雨板的长,度,在判断x1-last为否小于0,如果小于0说明有重复部分减去重复部分即可。

注意:如果当前板的x2小于last直接跳过这个板子,说明板完全被覆盖了。

如图:

 这种情况上面的板子被完全覆盖了,直接跳过。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
struct node
{
	int x1;
	int y1;
	int x2;
	int y2;
}q[N];
bool cmp(node n1,node n2)
{
	return n1.x1<n2.x1;
}
int main()
{
	int n;
	int a,b,c,d;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		cin>>a>>b>>c>>d;
		if(a<c)
		{
		  q[i].x1=a;
		  q[i].y1=b;
		  q[i].x2=c;
		  q[i].y2=d;	
		}
		else
		{
		  q[i].x1=c;
		  q[i].y1=d;
		  q[i].x2=a;
		  q[i].y2=b;
		}
	}
	sort(q,q+n,cmp);
	int last=q[0].x1;
	long long ans=0;
	for(int i=0;i<n;i++)
	{
		if(q[i].x2<=last)
		continue;
		ans+=q[i].x2-q[i].x1;
		int add=last-q[i].x1;
		if(add>0)
		ans-=add;
		last=q[i].x2; 
	}
	cout<<ans;
}

A、Mio visits ACGN Exhibition

 题目大意:给一个n行m列的01矩阵以及p,q,从(0,0)出发只能向右或向下走到(n,m),问有多少条路径其走过的0的个数不少于p,1的个数不少于q,输出取模后的条数。

看到取模就想到跑dfs必炸,还是跑了一遍试试,过了6个点炸了。

正确的做法应该是dp,f[i][j][k]表示走到(i,j)并且正好经过k个0的走法,但是三维数组开不了那么大,所以用滚动数组减少一维度变成f[j][k].

那么状态转移方程为:

a[i][j]=1,f[j][k]=f[j][k]+f[j-1][k];

a[i][j]=0,f[j][k]=f[j-1][k-1]+f[j][k-1];

i,j从小到大遍历,k从大到小遍历。如果j更小,表示f[j]已被更新则表示的是f[i][j]的状态,否则还没被更新表示的是f[i-1][j]的状态。k如果更小,则还没被更新。从(0,0)到(n,m)一共走过了n+m-1个点,最后累加符合条件的即可。

H、Hearthstone So Easy

题目大意:两个人玩游戏每个人都有n滴血以及一个k,轮流进行操作,操作分为两个阶段,①操作开始前,当前是第几轮就扣几滴血②选择恢复自己k滴血或减少对方k滴血。一个人血量先为0那么另一个人取胜。

两个人起始血量一样,如果两个人回合开始前的血量仍然一样的话,那么先手必败。后手是明白这一点的,所以如果先手回血,后手就让先手扣血,反之后手就让先手回血,这样子两人每回合开始血量都一样,那么后手必赢。所以除非先手在一开始就能杀死后手,后手必赢。

如果n为1的话先手也必输,特判一下。

#include<bits/stdc++.h>
using namespace std;
int t,n,k;
int main()
{
    cin>>t;
    while(t--)
    {
     cin>>n>>k;
        if(k+1>=n)
        cout<<"pllj"<<endl;
        else
        cout<<"freesin"<<endl;
    }
    return 0;
}

J、LRU

逆天题,本身不算难但是题面晦涩难懂极其逆天

 

 题目大意:有n个数依次进入缓冲区,如果这个数已经存在那么就代替更早进入的这个数并且缓冲次数+1;如果没有这个数并且已经满了,就删除最早进入的数该数再进去,如果没满就进入。

求最小的缓冲区容量使得缓冲次数不小于k。

一眼二分找左边界,check函数用容器模拟即可。看代码吧

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef pair<int,int> PII;
int a[N];
bool ans=false;
int res;
int n,k;
bool check(int mid)
{
	int cnt=0;
	set<PII>st;
	map<int,int>mp;
	for(int i=1;i<=n;i++)
	{
		if(mp.count(a[i]))//已经在里面了
		{
			cnt++;
			st.erase(make_pair(mp[a[i]],a[i]));
	
			mp[a[i]]=i;
			st.insert(make_pair(i,a[i]));
			continue;
		}
		else if(st.size()==mid)//没在里面并且满了
		{
			 PII it=*st.begin();
			 st.erase(st.begin());
			 mp.erase(it.second);
			 st.insert(make_pair(i,a[i]));
			 mp[a[i]]=i; 
			 continue;
		}
		else//没在里面并且没满
		{
			mp[a[i]]=i;
			st.insert(make_pair(i,a[i]));
		}
	}
	if(cnt>=k)
	{
	ans=true;
	return true;
    }
	else
	return false;
}
int main()
{
	scanf("%d %d",&n,&k);
	for(int i=1;i<=n;i++)
	scanf("%d",&a[i]);
	int l=1,r=n,mid;
	while(l<=r)
	{
		mid=(l+r)/2;
		if(check(mid))
        r=mid-1,res=mid;
        else
        l=mid+1;
	}
	if(!ans)
	printf("cbddl\n");
	else
	printf("%d",l);
	return 0;
} 

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值