专项训练---省赛模拟

12 篇文章 1 订阅
11 篇文章 0 订阅

1. 战争(war)

题目描述

Yjt 拥有庞大的后宫,但是最近他很烦恼。

他的 n 个后宫住在连续的一排 n 个房间里,每个房间只住一个人,编号为 1..n。他的后

宫来自 m 个不同的国家,每个国家的语言不同,一旦相邻的两个房间住着来自相同国家的

人,她们就会发生争吵,然后爆发可怕的战争,使 yjt 后宫失火。因为后宫实在太多,yjt 也

不知道她们分别来自什么国家,每个后宫都可能是 m 个国家中的任意一个。Yjt 想知道,有

多少种可能的状态会发生战争。

输入格式

第一行两个正整数 m,n. 输出格式

一行一个自然数,表示可能的状态数。答案对 998244353 取模。

样例输入

2 3

样例输出

6

样例解释

可能的状态分别是:

第一个来自 1 国家,第二个来自 1 国家,第三个来自 1 国家

第一个来自 1 国家,第二个来自 1 国家,第三个来自 2 国家

第一个来自 1 国家,第二个来自 2 国家,第三个来自 2 国家

第一个来自 2 国家,第二个来自 2 国家,第三个来自 2 国家

第一个来自 2 国家,第二个来自 2 国家,第三个来自 1 国家

第一个来自 2 国家,第二个来自 1 国家,第三个来自 1 国家

数据范围

对于 30%的数据,n,m<=5;

对于 50%的数据,n,m<=1000000;

对于 100%的数据,n,m<=2147483647

#include<bits/stdc++.h>
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define mod 998244353 
using namespace std;
int n,m,ans=0;
int ksm(int a,int b){
    int ans=1;
    for(;b;a=(a*a)%mod,b>>=1)
        if(b&1) ans*=a,ans%=mod;
    return ans;
}
int main(){
    freopen("war.in","r",stdin);
    freopen("war.out","w",stdout);
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>m>>n;
    long long ex=(ksm(m,n)%mod-m*ksm(m-1,n-1)%mod)%mod;
    ex+=(ex<0?mod:0);
    cout<<ex;
    return 0;
}


2.字母(letter)

题目描述

现在有 n 个字母,每个字母都有价值 v[i]和个数限制 num[i]。现在要构造一个任意长度

的串。定义串的价值为:第 1 位字母的价值*1+第 2 位字母的价值*2+第 3 位字母的价值*3。

求能构造出的最大的串的价值。注意由于这个串可以是空的,所以价值一定不会小于 0. 输入格式

第一行一个整数 n,表示字母的数目。

接下来 n 行每行两个数 v[i],num[i],意义如题目所示。

输出格式

一行一个整数表示最大的串的价值。

样例输入

3

-5 3

2 1

1 1

样例输出

5

数据范围

对于 30%的数据,n<=10;

对于另外 20%的数据,v[i]>=0;

对于 100%的数据,n<=100000,|v[i]|<=100,num[i]<=10。

#include<bits/stdc++.h>
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
using namespace std;
int n,l=0,b[1000009];
long long ans=0,ex=0;
struct node{
    int v,num;
}a[100009];
bool cmp(int x,int y){
    return x>y;
}
int main(){
    freopen("letter.in","r",stdin);
    freopen("letter.out","w",stdout);
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i].v>>a[i].num;
        while(a[i].num--) b[++l]=a[i].v;
    }
    sort(b+1,b+l+1,cmp); 
    for(int i=1;i<=l;i++){
        b[i]+=b[i-1];
    }
    for(int i=1;i<=l;i++){
        ans=max(ans,ans+b[i]);
    }
    cout<<ans;
    return 0;
}

离散化+前缀和

#include<bits/stdc++.h>
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define N 100086
#define ll long long
using namespace std;
/*int read(){
 int x=0,f=1;char ch=getchar();
 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 while(ch>='0'&&ch<='9'){x=x*10+ch-'0',ch=getchar();}
 return x*f;
}*/
struct data{int val,cnt;}a[N];
bool cmp(data a,data b){return a.val>b.val;}//从大到小排 
int main(){
 freopen("letter.in","r",stdin);
 freopen("letter.out","w",stdout);
 ios::sync_with_stdio(false);
 cin.tie(0);
 cout.tie(0);
 int n;cin>>n;//=read();
 for(int i=1;i<=n;i++){
    cin>>a[i].val>>a[i].cnt;//=read();
    }
 sort(a+1,a+n+1,cmp);
 ll now=0,cnt=0,ans=0;
 for(int i=1;i<=n;i++)
  for(int j=1;j<=a[i].cnt;j++){
   cnt+=a[i].val;//前缀和,实现a[i].val*i 
   now+=cnt;
   ans=max(ans,now);
  }
 printf("%lld\n",ans);
 return 0;
}

只有前缀和

3.约数研究(number)

题目描述 定义 f(x)为 x 的约数个数。例如 f(2)=2,f(6)=4。给定 n,求出 f(1)到 f(n)的和。 输入格式 一行一个正整数 n。 输出格式 一行一个数表示答案。 样例输入 3 样例输出 5 数据范围 对于 30%的数据,n<=1000; 对于 50%的数据,n<=200,000. 对于 70%的数据,n<=5,000,000; 对于 100%的数据,n<=10^10;

#include<bits/stdc++.h>
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
using namespace std;
int main(){
 freopen("number.in","r",stdin);
 freopen("number.out","w",stdout);
 ios::sync_with_stdio(false);
 cin.tie(0);
 cout.tie(0);
 int n;
 unsigned long long ans=0;
 cin>>n;
 for(int i=1;i<=n;i++)
  ans+=n/i;
 cout<<ans<<endl;
 return 0;
}

信手拈来的骗分,直上70

#include<bits/stdc++.h>
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
using namespace std;
int n;
ll ans=0;
int main(){
    freopen("number.in","r",stdin);
    freopen("number.out","w",stdout);
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    scanf("%d",&n);
    for(int l=1,r;l<=n;l=r+1){
          ll i=n/l;
          r=n/i;
          ll len=r-l+1;
          ans+=len*i;
    }
    cout<<ans<<endl;
    return 0;
}

亿点点,边界优化,拿下100

4.灯(light)

题目描述 月月立志要做一个合格的女仆。 这天晚上月月要关掉楼里所有的灯。这个楼有 n 层,每层有 m 个房间,每层的两侧有 楼梯,只能从楼梯上下楼。每个房间里的灯开关状态由一个大小为 n*(m+2){包括两边的楼 梯}的 01 矩阵表示,0 代表关着的,1 代表开着的。每次向左或者向右移动一格会消耗一分 钟,从楼梯上下楼也会消耗一分钟,但是走到房间里关灯不需要消耗时间。一开始月月在矩 阵左下角,现在她想知道她最少需要多少分钟才能把所有的灯全部关上。 输入格式 第一行包含两个正整数 n,m,表示楼有 n 层,每层 m 个房间。 接下来 n 行每行 m+2 个整数,表示这一层 m 个房间的状态。注意楼梯的部分始终是 0。 输出格式 一行一个整数表示答案。 样例输入 3 4 001000 000010 000010 样例输出 12 数据范围 对于 30%的数据,n*m<=12 对于 100%的数据,n<=8,m<=100

#include<bits/stdc++.h>
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
using namespace std;
typedef long long ll;
ll  l[155],r[155],mx,n,m,ans;
char a[155][155];
void dfs(ll i,ll lr,ll now)//当前第i行,lr是在左边1还是右边2 now当前的时间 
{
 if(i==mx){
  if(l[i]==0) {ans=min(now,ans);return;}
  if(lr==1){//lr是在左边
   now+=r[i]-1;
  }
  else{
   now+=m+2-l[i];
  }
    ans=min(now,ans);return ; 
 }
 if(lr==1){//在左边 
  if(l[i]==0){//这行没有要关的灯 
     dfs(i+1,1,now+1);}// 下一行 
  else{dfs(i+1,1,now+2*(r[i]-1)+1);}//这边有要关的灯,关完再原路回 
  dfs(i+1,2,now+m+2); //粗爆走一行 走到最右边 
 }
 else{//在右边 
   if(l[i]==0)  dfs(i+1,2,now+1); else dfs(i+1,2,now+2*(m+2-l[i])+1);
    dfs(i+1,1,now+m+2); 
 }
}
int main()
{
 freopen("light.in","r",stdin);
 freopen("light.out","w",stdout);
 ios::sync_with_stdio(false);
 cin.tie(0);
 cout.tie(0);
 cin>>n>>m;getchar();
 mx=1;
 for(ll i=n;i>=1;i--){ 
   for(ll j=1;j<=m+2;j++)
   {
       a[i][j]=getchar();
    if(a[i][j]=='1')//如果当前行有灯要关 
    {
     if(l[i]==0){ //i行第一次遇到有灯要关 
      l[i]=j;//记录亮灯所在的列 
     }
     r[i]=j;//记录当前行右边界1 
   if(mx==1) mx=i;//mx记录有灯的最大行号 
  }
   }getchar();
 } 
   ans=6147483647;
   dfs(1,1,0);
   cout<<ans<<endl;
   return 0;
}

dfs遍历,getchar()读字符,(居然是读字符串,奇坑)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值