2019icpc上海网络赛

比赛链接:The Preliminary Contest for ICPC Asia Shanghai 2019

L. Digit sum

签到题

题目大意:给出n,b,求1-n 的b进制的各个位数之和

思路:因为n就到10^6可以直接预处理打表。   或者也可以数位DP

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define ll long long
const int N=1000005;
ll a[12][N];
ll fun(int b,int x)
{
    int ans=0;
    while(x)
    {
        ans+=x%b;
        x/=b;
    }
    return (ll)ans;
}
void init()
{
    for(int i=2;i<=10;i++)
        a[i][1]=1;
    for(int i=2;i<=10;i++)
    {
        for(int j=2;j<=1000000;j++)
            a[i][j]=a[i][j-1]+fun(i,j);
    }
}
int main()
{
    init();
    int t,T=1;
    scanf("%d",&t);
    while(t--)
    {
        int n,b;
        scanf("%d%d",&n,&b);
        printf("Case #%d: %lld\n",T++,a[b][n]);
    }
    return 0;
}

 

B. Light bulbs

题目大意:有编号为0~N-1的灯泡,初始都是关闭的,M次操作,每次操作把一个区间 [L,R] 的灯泡改变状态,问最后打开的灯有多少个。

思路:把区间的左端点,右端点进行排序,差分思想,把左端点权值赋为1,右端点赋为-1,前缀和求两个相邻端点间的灯泡状态。  不能直接对n个灯泡差分,T:10^3,N:10^6 ,O(TN)超时

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct node
{
    int id,val;
}e[2005];
bool cmp(node a,node b)
{
    return a.id<b.id;
}
int main()
{
    int t,T=1;
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        int l,r,cnt=0;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&l,&r);
            l++,r++;
            e[cnt].val=1,e[cnt++].id=l;
            e[cnt].val=-1,e[cnt++].id=r+1;
        }
        e[cnt].val=0,e[cnt++].id=n+1;
        sort(e,e+cnt,cmp);
        int ans=0,res=0;
        for(int i=0;i<cnt;)
        {
            int k=0,x=e[i].id;
            while(e[i].id==x)
            {
                k+=e[i].val;
                i++;
            }
            res+=k;
            if(res%2) ans+=e[i].id-x;
        }
        printf("Case #%d: %d\n",T++,ans);
    }
    return 0;
}

 

 J. Stone game

题目大意:有n堆石头,给出每堆石头的数量,问有多少个集合满足:

1. 集合内的每一堆石头数量的和a >=  集合外的所有石头堆的石头数量和b  

2.集合内去掉任意一个石头堆后的数量 a-p <=b  (去掉任何一个都满足即去掉最小的满足,所以p就是集合中石头数量的最小值)

根据题目即可列出:  (x==a-p , y==b)
1.  x+p+y= sum  (n堆石头的总数量)                                                                                                                                                  2.  x+p>=y
3.  x<=y

求得: sum/2-p  <= x  <=  (sum-p)/2

思路:把石头从大到小排序,dp[ i ] [ j ] 表示第i堆石头为最小的时候,集合内的x为 j 的集合的个数,求 i 为1~n,j 满足上面所得公式的集合的总个数

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define ll long long
const int N=150005;
const ll mod=1000000007;
int a[305];
ll dp[N];
bool cmp(int a,int b)
{
    return a>b;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,sum=0;
        scanf("%d",&n);
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
            sum+=a[i];
        }
        sort(a+1,a+n+1,cmp);
        ll ans=0;
        for(int i=1; i<=sum; i++) dp[i]=0;
        dp[0]=1;
        for(int i=1; i<=n; i++)
        {
            int l=(sum+1)/2-a[i],r=(sum-a[i])/2;
            for(int j=l; j<=r; j++)
                ans=(ans+dp[j])%mod;
            for(int j=sum-a[i]; j>=0; j--)
                dp[j+a[i]]=(dp[j+a[i]]+dp[j])%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

 F. Rhyme scheme

题意:输出长度为n的第k个Rhyme scheme
.•
Rhyme scheme: 长度为n的个数是bell number的例子。
如果不懂bell number也没有关系。
Rhyme scheme就是第i个字母最多是前面出现过的字母+1.
比如:AAC是不可以的,ABCAAD是可以的,ABBD也是不可以的

思路:f[ i ] [ j ] 表示长度为i+1且第一位的字符为'A'+j 的满足上面条件的字符串的个数。

代码:

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

__int128 f[30][30];
void init()
{
    for(int i=0;i<=26;i++) f[0][i]=1;
    for(int i=1;i<=26;i++)
        for(int j=0;j<=26;j++)
        f[i][j]=f[i-1][j]*j+f[i-1][j+1];
}
int main()
{
    init();
    int t,T=1;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        __int128 m=0;
        char s[30];
        scanf("%d%s",&n,s);
        int len=strlen(s);
        for(int i=0;i<len;i++)
            m=m*10+(s[i]-'0');
        int c=1;
        printf("Case #%d: ",T++);
        printf("A");
        for(int i=2;i<=n;i++)
        {
            int k=0;
            for(int j=1;j<=c;j++)
            {
                if(m<=f[n-i][c]) break;
                m-=f[n-i][c];
                k=j;
            }
            printf("%c",'A'+k);
            c=max(c,k+1);
        }
        printf("\n");
    }
    return 0;
}

 

 G. Substring

题意:给了一个母串S, 每次循环给了一个模板串P,问模板串在母串中“匹配”了多少次?“匹配”的意思就是首字母和尾字母一样,中间字母顺序可以换。

思路: 用滑动窗口,对于长度一样的询问可以弄在一起搞,因为窗口大小是一样的。用map[ i ][ j ] [hash] 记录长度为k的且以 i开头,以j 结尾,哈希值为hash的子串的个数

代码:

#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
const int N=1e5+7;
const int mod=1e9+7;
char s[N],p[N];
ull ha[30];
map<ull,int>qu[30][30];
map<ull,int>ans[30][30];
struct node
{
    int fi,en,siz,id;
    ull ha;
}e[N<<1];
void init()
{
    ha[0]=N;
    for(int i=1;i<26;i++)
        ha[i]=(ha[i-1]*N)%mod;
}
bool cmp(node a,node b)
{
    return a.siz<b.siz;
}
int len,n,qa[N<<1];
void solve(int x)
{
    if(x>len) return;
    ull hap=0;
    int i=0,j=x-1;
    for(int k=i;k<=j;k++) hap=(hap+ha[s[k]-'a'])%mod;
    if(qu[s[i]-'a'][s[j]-'a'].count(hap)) ans[s[i]-'a'][s[j]-'a'][hap]++;
    while(j<len-1)
    {
        hap=(hap-ha[s[i]-'a']+mod)%mod;
        i++,j++;
        hap=(hap+ha[s[j]-'a'])%mod;
        if(qu[s[i]-'a'][s[j]-'a'].count(hap)) ans[s[i]-'a'][s[j]-'a'][hap]++;
    }
}
int main()
{
    init();
    int t;
    scanf("%d",&t);
    while(t--)
    {
        for(int i=0;i<26;i++)
            for(int j=0;j<26;j++)
        {
            qu[i][j].clear();
            ans[i][j].clear();
        }
        scanf("%s",s);
        len=strlen(s);
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%s",p);
            int siz=strlen(p);
            e[i].siz=siz;
            e[i].fi=p[0]-'a';
            e[i].en=p[siz-1]-'a';
            e[i].id=i;
            ull res=0;
            for(int j=0;j<siz;j++)
                res=(res+ha[p[j]-'a'])%mod;
            e[i].ha=res;
            qu[e[i].fi][e[i].en][res]=1;
        }
        sort(e,e+n,cmp);
        for(int i=0;i<n;i++)
        {
            if(e[i].siz!=e[i-1].siz) solve(e[i].siz);
            qa[e[i].id]=ans[e[i].fi][e[i].en][e[i].ha];
        }
        for(int i=0;i<n;i++)
            printf("%d\n",qa[i]);
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值