2021江西省icpc(A,B,D,F,G,H,J,K,L)

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

任意门

先从最简单的签到题开始吧

#include<iostream>
#include<cstdio>
#include<math.h>
#include<algorithm>
#include<cstring>
#include<queue>

using namespace std;

long long ans;
long long f(int n)
{
    if(n<=0)return 0;
    ans=n*n+f(n-1);
    return ans;
}
int main()
{
  int t;
  cin>>t;
  while(t--)
  {
      ans=0;
      int n,m;
      cin>>n>>m;
      ans=f(n);
      printf("%d\n",ans*m);
  }
  return 0;
}

L、It Rains Again

​​​​​​任意门​​​​​

题意:给你两个坐标,看他能覆盖x有多长,这个比较标准的差分。只用考虑到他是否覆盖到这个区域,即差分数组的数组元素为正数的个数。

#include<iostream>
#include<cstdio>
#include<math.h>
#include<algorithm>
#include<cstring>
#include<queue>
#include <math.h>

using namespace std;

int a[100010];
int main()
{
    int t,_max=-1;
    cin>>t;
    while(t--)
    {
     int x1,y1,x2,y2;
     cin>>x1>>y1>>x2>>y2;
        a[x1]++;
        a[x2]--;//差分
        _max=max(_max,max(x1,x2));
    }
    int ans=0;
    for(int i=0;i<=_max;i++)
        {
           a[i]+=a[i-1];
           if(a[i])
            ans++;
        }
    cout<<ans<<endl;
    return 0;
}

B、Continued Fraction

任意门​​​​​​ 

 

题意:其实就是递归。但是我这一题的代码实现有点慢,希望自己在代码实现上面有一定突破。

#include<iostream>
#include<cstdio>
#include<math.h>
#include<algorithm>
#include<cstring>
#include<queue>

using namespace std;

int _count=1;
queue<int>q;
void f(int x,int y)
{

    int m=y/x;
   q.push(m);
   _count++;
   if(y%x==0){
        cout<<_count-1<<" ";
   return;}
   f(y-m*x,x);
}

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        _count=1;
        int x,y;
        cin>>x>>y;
        int m=x/y;
      q.push(m);
        f(x-m*y,y);
        while(1)
        {
            if(q.empty()==0)
            {
                int t=q.front();
                printf("%d ",t);
                q.pop();
            }
            else break;
        }
        cout<<endl;
    }
    return 0;
}

A、Mio visits ACGN Exhibition(dp)

任意门

题意:就是从给你n*m的矩阵的左上角(1,1)一直走到右下角(n,m),每一个方块呢,他都被赋予了值,要么0,要么1,然后问你有多少种路径,然后对走的路径也有一定的要求就是0的个数至少是p个,1的个数至少是q个。一开始对这道题的类型分析错了,以致看另外一道题去了,呜呜。

这里就涉及到了用滚动数组优化dp。

滚动数组是一种能够在动态规划中降低空间复杂度的方法,有时某些二维dp方程可以直接降阶到一维,在某些题目中甚至可以降低时间复杂度,是一种极为巧妙的思想。通过观察dp方程来判断需要使用哪些数据,可以抛弃哪些数据,一旦找到关系,就可以用新的数据不断覆盖旧的数据量来减少空间的使用。

完全背包的二维压成一维,这里借鉴了我们学校大佬的方法。大佬!

#include<iostream>
#include<cstdio>
#include<math.h>
#include<algorithm>
#include<cstring>
#include<queue>
#include <math.h>

using namespace std;

#define mod 998244353
const int N=1005;
long long a[N][N];
long long f[N][N];
signed main()
{
   // cout<<mod<<endl;
    int n,m,p,q;
    cin>>n>>m>>p>>q;
    for(int i=1; i<=n; i++)
        for(int j=1; j<=m; j++)
        {
            cin>>a[i][j];
        }
    if(!a[1][1])
        f[1][1]=1;
    else f[1][0]=1;
    for(int i=1; i<=n; i++)
        for(int j=1; j<=m; j++)
        {
            if(i!=1||j!=1)
            {
                if(a[i][j])
                    for(int k=i+j-1; k>=0; k--)
                        f[j][k]=(f[j-1][k]+f[j][k])%mod;//dp的转移方程
                else
                {
                    for(int k=i+j-1; k; k--)
                        f[j][k]=(f[j-1][k-1]+f[j][k-1])%mod;
                    f[j][0]=0;
                }
            }
        }
    int ans=0;
    for(int i=p; i<=n+m-q-1; i++)
    {
        ans+=f[m][i];
        ans%=mod;
    }
    cout<<ans<<endl;
}

D、Character Distance 

任意门

这是一道都构造题。字典序。我练得比较少,队友负责,但是有一点弄错了,就是如果x只出现一次,ij不成对出现,那么就直接顺序输出,而不是"-1"

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
typedef long long ll;
int a[N];
int b1[N],b2[N],b[N];
int pos,nb;
map<int,int> mp;
int main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int t;
	cin>>t;
	while(t--){
		mp.clear();
		ll n,d;int flag=0;
		int pos1=-0x3f3f3f3f,pos2=-0x3f3f3f3f,nb1=0,nb2=0;
		cin>>n>>d;
		for(int i=1;i<=n;i++){
			cin>>a[i];
			mp[a[i]]++;
		}
        for(int i=1;i<=n;i++){
			if(mp[a[i]]==1){
                flag=1;break;//这就是我们没有考虑到的情况,如果x只出现一次
                //那么按照顺序输出
            }
		}
        sort(a+1,a+n+1);
        if(d==1||flag==1){
			for(int i=1;i<=n;i++)cout<<a[i]<<' ';
			cout<<endl;
			continue;
		}
		if(d>=n){ 
			cout<<-1<<endl;
			continue;
		}
		for(int i=n;i>0;){
			//cout<<i<<endl; // 尾 
			ll num=mp[a[i]];
			
			ll cha=(1ll*num-1ll)*(1ll*d-1ll)-(1ll*n-1ll*i);//所需长度和已给长度的比较
			if(cha<=0){//后面够
				
				if(pos1<(i-num+1)){
					pos1=i-num+1;
					nb1=a[i];
					
				}
			}
			else{//后面不够 
				int head=i-num+1;
				if(pos2<=(head-cha)&&(head>cha)){
					pos2=head-cha;//放头位置 
					nb2=a[i];
				}
			}
			i-=num;
		}
		if(pos1<1&&pos2<1){
			cout<<"-1"<<endl;
			continue;
		}
        if(pos1>0){
            int num=mp[nb1],pos=pos1;int j=1,cnt=0;
            for(int i=1;i<=n;i++){
                if(a[j]==nb1){
                    j+=num;
                }
                if(i==pos&&cnt<num){
                    b1[i]=nb1;
                    pos+=d;cnt++;
                }
                else{
                    b1[i]=a[j++];
                }	
            }
        }
        if(pos2>0){
            int num=mp[nb2],pos=pos2;int j=1,cnt=0;
            for(int i=1;i<=n;i++){
                if(a[j]==nb2){
                    j+=num;
                }
                if(i==pos&&cnt<num){
                    b2[i]=nb2;
                    pos+=d;cnt++;
                }
                else{
                    b2[i]=a[j++];
                }	
            }
        }
        if(pos1<1)
             for(int i=1;i<=n;i++){
                 cout<<b2[i]<<' ';
             }
        else if(pos2<1)
            for(int i=1;i<=n;i++){
                 cout<<b1[i]<<' ';
            }
        else{
            int f=0;
            for(int i=1;i<=n;i++){
                if(b1[i]!=b2[i]){
                    if(b1[i]>b2[i])f=2;
                    else f=1;
                    break;
                }
            }
            if(f==1){
                for(int i=1;i<=n;i++){
                    cout<<b1[i]<<" ";
                }
            }else{
                for(int i=1;i<=n;i++){
                    cout<<b2[i]<<" ";
                }
            }
        }		
		cout<<endl;
	}
	
	return 0;
}

H、Hearthstone So Easy

这一道题就是如果他在第一手的时候没有杀掉对方,那么如果两个人一起回血,那么这个局面就进入了僵持的局面,那么这个时候杀不死后手,后手肯定会赢的,所以如果一开始没有杀死后手,那么后手必赢,这个时候还有一点很重要的就是,特判n==1.

#include<iostream>
#include<cstring>
#include<math.h>
#include<map>
#include<algorithm>
#define PI acos(-1)
using namespace std;

int main()
{
   int T;
   cin>>T;
   while(T--)
   {
       int n,k;
       cin>>n>>k;
       if(n==1)cout<<"freesin"<<endl;
       else if(1+k>=n)cout<<"pllj"<<endl;
       else cout<<"freesin"<<endl;
       
   }
    return 0;
}

J、LRU

任意门

这个就是操作系统中LRU,然后呢,模拟一边,给你序列的长度n和需要命中的次数k。

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N = 1e5 + 10;
int a[N];

struct node {
    int idx, val;
    bool operator<(const node& a) const { return idx < a.idx; }
};

inline bool check(int x, int n, int k){
    set<node> se;//维护LRU表
    unordered_map<int, int> mp;//维护出现的次数
    int cnt = 0;
    for (int i = 1; i <= n; ++i) {
        if (mp.count(a[i])) {//如果已经出现,只需要替换就可以了
            ++cnt;
            se.erase({mp[a[i]], a[i]});
            se.insert({i, a[i]});
            mp[a[i]] = i;
            continue;
        } 
        if (se.size() == x) {//如果满了且并没有出现过,则需要删除最先的数
            node top = *se.begin();
            se.erase(se.begin());
            mp.erase(top.val);
        }
        mp[a[i]] = i;//直接加进去
        se.emplace(node{i, a[i]});
    }
    return cnt >= k;
}

signed main(){
    int n, k; cin >> n >> k;
    for(int i = 1; i <= n; i++) cin >> a[i];
    int l = 1, r = n + 1, ans = -1;
    while(l <= r){//二分寻找答案
        int mid = l + r >> 1;
        if(check(mid, n, k)) r = mid - 1, ans = mid;
        else l = mid + 1;
    }
    if(ans < 0) puts("cbddl");
    else printf("%lld\n", ans);
    return 0;
}

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值