2019牛客暑期多校训练营(第七场)

A String

题意:给一个01串,把该串划分,使得每个子串都是所在串形成的环中字典序最小的。
题解:把01串中以1、0分界处都拆开,对拆分出来的子串我们再两两比对,可以合并则合并。队友AC代码

#include
#define LL long long
#define ms0(x) memset(x,0,sizeof(x))
#define ms-1(x) memset(x,-1,sizeof(x))
bool vis[300];
using namespace std;
int pos[300];
string save[300];
struct node{
    string str;
    int num_0;
    int num_1;
    node(string a):str(a)
    {
        num_0=0;int j=0;
        for(;j<str.size();j++)
        {
            if(a[j]=='1')
                break;
        }
        num_0=j;
        num_1=str.size()-num_0;
    }
    node(){
    }
    bool operator >(const node & tmp)const{
        string tmp1,tmp2;
        tmp1=str+tmp.str;
        tmp2=tmp.str+str;
        return tmp1<=tmp2;
//      if(tmp.num_1==0)
//      {
//          if(num_1==0)
//              return true;
//          else
//              return false;
//      }
//      if(num_0==tmp.num_0)
//          return num_1<=tmp.num_1;
//      else
//          return num_0>tmp.num_0;
    }
}ans[300];
int main()
{
    ios::sync_with_stdio(false);
    int t;
    cin>>t;string str;
    while(t--)
    {
        cin>>str;
        pos[0]=-1;
        memset(vis,0,sizeof(vis));
        int cnt=1;
        for(int j=0;j<str.size();j++)
        {
            if(str[j]=='1'&&j<str.size()-1&&str[j+1]=='0')
            {
                save[cnt]=str.substr(pos[cnt-1]+1,j-pos[cnt-1]);
                pos[cnt]=j;
                cnt++;
            }
        }
        save[cnt]=str.substr(pos[cnt-1]+1,str.size()-1-pos[cnt-1]);
        pos[cnt]=str.size()-1;
        cnt++;
        int ans_num=1;
        ans[1]=node(save[1]);
        for(int j=2;j<cnt;j++)
        {
            node tmp=node(save[j]);
            if(ans[ans_num]>tmp)
            {
                ans[ans_num].str+=tmp.str;
            }
            else
            {
                ans[++ans_num]=tmp;
            }
        }
        while(ans_num>1)
        {
            int tmpnum=1; bool flag=0;
            for(int j=2;j<=ans_num;j++)
            {
                if(ans[tmpnum]>ans[j])
                {
                    ans[tmpnum].str+=ans[j].str;
                    flag=1;
                }
                else
                {
                    ans[++tmpnum]=ans[j];
                }
            }
            ans_num=tmpnum;
            if(flag==0)
                break;
        }
        for(int j=1;j<=ans_num;j++)
            cout<<ans[j].str<<" ";
        cout<<endl;
//      for(int j=1;j
//      {
//          cout<
//      }
//      cout<
    }
     
    return 0;
}

B Irreducible Polynomial

(窝太菜了做题太少,没发现是原题POJ2126)
题意:给一个多项式的系数 a n 、 a n − 1 、 . . . a 1 、 a 0 a_n、a_{n-1}、...a_1、a_0 anan1...a1a0,问该多项式是否可以继续分解。
题解:有个结论,系数大于3时一定是可以继续拆解的,系数小于<2时显然不能继续拆解;系数等于2时我们再用一元二次方程求根公式判断下。(对不起高代老师QAQ,明明上课学过的)

#include
#define LL long long
#define ms0(x) memset(x,0,sizeof(x))
#define ms-1(x) memset(x,-1,sizeof(x))
int num[23];
using namespace std;
int main()
{
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        for(int j=1;j<=n+1;j++)
                cin>>num[j];
        if(n>2)
        {
             
            cout<<"No"<<endl;
        }
        else
        {
            if(n<2)
                cout<<"Yes"<<endl;
            else
            {
                if(num[2]*num[2]-4*num[1]*num[3]>=0)
                {
                    cout<<"No"<<endl;
                }
                else
                    cout<<"Yes"<<endl;
            }
        }
    }
    return 0;
}

C Governing sand

题意:给定n棵树,每棵树有高度hi、被砍需要的代价ci、数量pi,为了防风沙,需要把这些树形成一个防风墙,条件是最高的树超过(划重点)当前所有树的一半
题解:利用了ci只有200的限制,用ci存储对应的数量和花费,把树按高度从大到小,每次砍树时贪心的坎代价小的树,每次移动更新下ci数组的值即可,复杂度O(200*n)
PS:比赛时坑队友了,各种地方没开ll,more than这么显眼的字没看

#include
using namespace std;
#define ll long long
const int maxn=100010;
const int maxm=220;
#define inf 0x3f3f3f3f3f3f3f3f
 
int n;
ll Count[maxm];
ll cost[maxm];
 
struct node{
    ll h,c,p;
}tr[maxn];
bool cmp(const node &x,const node &y)
{
    return x.h>y.h;
}
 
int main()
{
    while(~scanf("%d",&n)){
        int m=200;
        for(int i=0;i<=m;i++) Count[i]=cost[i]=0;
        ll all=0;//number of trees
        ll h,c,p;
        for(int i=1;i<=n;i++){
            scanf("%lld%lld%lld",&h,&c,&p);
            tr[i].h=h;tr[i].c=c;tr[i].p=p;
            Count[c]+=p;
            all+=p;
            cost[c]+=1LL*c*p;
        }
        sort(tr+1,tr+1+n,cmp);
        ll ans=inf;
        ll tmp,pre=0,pre2=0;//pre2 高于当前树的树数量 pre高于当前树的树cut代价
         
        for(int i=1,k;i<=n;i=k+1){
            tmp=pre;
            ll num=0;
            for(k=i;k<=n&&tr[k].h==tr[i].h;k++) num+=tr[k].p;//
            k--;//
            pre2+=num;//pre2 + num
            num=max(all-pre2-num+1,0LL);//多坎一棵
             
            for(int j=i;j<=k;j++){
                Count[tr[j].c]-=1LL*tr[j].p;
                cost[tr[j].c]-=1LL*tr[j].p*tr[j].c;
                pre+=1LL*tr[j].p*tr[j].c;
            }
             
            for(int j=0;j<=m&&num;j++){
                if(Count[j]){
                    if(num>=Count[j]) num-=Count[j],tmp+=cost[j];
                    else tmp+=1LL*j*num,num=0;
                }
            }
            ans=min(ans,tmp);
             
 
        }
        printf("%lld\n",ans);
    }
    return 0;
}

D Number

题意:给n和p,求能被p整除的数位长为n的数,只需地位补零即可。

#include
using namespace std;
#define ll long long
const int maxn=100010;

int getl(int x)
{
	int num=0;
	while(x){
		num++;
		x/=10;
	}
	return num;
}

int main()
{
	int n,p;
	while(~scanf("%d%d",&n,&p)){
		int len=getl(p);
		if(len<=n){
			printf("%d",p);
			for(int i=len+1;i<=n;i++) printf("0");
			
		}else{
			printf("T_T");
		}
		printf("\n");
	}
	return 0;
}

E Find the median(线段树查询区间第K大+离散化)

题意:给n个操作,每次加入[l,r]这些数,加完后问当前的中位数
题解:线段树,每次更新线段,求当前线段树的中间值,难点是对于区间的离散化。

(区间修改也可以离散化的说

#include
using namespace std;
const int maxn=400010*2;
#define inf 0x3f3f3f3f
#define ll long long

int n;
int L[maxn],R[maxn];
int h[maxn*2],tot;
ll sum[maxn<<2];
ll lazy[maxn<<2];
void pushup(int rt)
{
	sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void pushdown(int rt,int l,int r)
{
	lazy[rt<<1]+=lazy[rt];
	lazy[rt<<1|1]+=lazy[rt];
	int m=(l+r)>>1;
	//注意这里 需要乘以(h[]) 
	sum[rt<<1]+=lazy[rt]*(h[m]-h[l-1]);
	sum[rt<<1|1]+=lazy[rt]*(h[r]-h[m]);
	lazy[rt]=0;
}
void build(int rt,int l,int r)
{
	if(l==r){
		sum[rt]=0;return;
	}
	int m=(l+r)>>1;
	build(rt<<1,l,m);
	build(rt<<1|1,m+1,r);
	pushup(rt);
}
void update(int rt,int l,int r,int a,int b)
{
	if(l>=a&&r<=b){
		sum[rt]+=h[r]-h[l-1];//加的是实际个数,需要用到h[] 
		lazy[rt]++;
		return;
	}
	if(lazy[rt]) pushdown(rt,l,r);
	int m=(l+r)>>1;
	if(a<=m) update(rt<<1,l,m,a,b);
	if(m<b) update(rt<<1|1,m+1,r,a,b);
	pushup(rt);
}

ll query(int rt,int l,int r,ll cur)
{
	if(l==r){
		ll k=sum[rt]/(h[r]-h[l-1]);//找出 当前区间覆盖了几次 
		return (cur+k-1)/k+h[l-1];//求cur到了哪一位 
	}
	if(lazy[rt]) pushdown(rt,l,r);
	int m=(l+r)>>1;
	if(cur>sum[rt<<1]) return query(rt<<1|1,m+1,r,cur-sum[rt<<1]);
	return query(rt<<1,l,m,cur);
}
int get(int x)
{
	return lower_bound(h+1,h+tot+1,x)-h;//返回离散化后的下标 
}
int main()
{
	int x1,x2,a1,b1,c1,m1;
	int y1,y2,a2,b2,c2,m2;
	while(~scanf("%d",&n)){
		scanf("%d%d%d%d%d%d",&x1,&x2,&a1,&b1,&c1,&m1);
		scanf("%d%d%d%d%d%d",&y1,&y2,&a2,&b2,&c2,&m2);
		//所有查询区间变成左开右闭
		L[1]=min(x1,y1);R[1]=max(x1,y1)+1;
		L[2]=min(x2,y2),R[2]=max(x2,y2)+1;
		tot=0;
		h[++tot]=L[1];h[++tot]=R[1];
		h[++tot]=L[2];h[++tot]=R[2];
		int x3,y3;
		for(int i=3;i<=n;i++){
			x3=((1LL*a1*x2%m1+1LL*b1*x1%m1)%m1+c1)%m1;
			y3=((1LL*a2*y2%m2+1LL*b2*y1%m2)%m2+c2)%m2;
			//原题Li Ri的生成分别是min+1 max+1 
			L[i]=min(x3,y3);//所有查询区间变成左开右闭 Li减 1 
			R[i]=max(x3,y3)+1;
			x1=x2;y1=y2;
			x2=x3;y2=y3;
			h[++tot]=L[i];h[++tot]=R[i]; 
		}
//		for(int i=1;i<=n;i++){
//			printf("L[%d]:%d R[%d]:%d\n",i,L[i]+1,i,R[i]);
//		}
		sort(h+1,h+tot+1);
		tot=unique(h+1,h+tot+1)-h-1;
		build(1,1,tot);
		ll all=0;
		for(int i=1;i<=n;i++){
			int l=get(L[i]),r=get(R[i]);
			update(1,1,tot,l+1,r);//这里传参注意把左边界+1 
			all+=(R[i]-L[i]);
			//这里的all相当于sum[1] 
			ll ans=query(1,1,tot,(all+1)/2);
			printf("%d\n",ans);
		}
	}
	return 0;
}
/*
2 4 1 8 3 8 0 3 6 9
0 1 2 3 3 4 6 8 8 9
0 1 2 3 4 6 8 9
*/

F Energy stones(树状数组+set)

参考:https://blog.csdn.net/kidsummer/article/details/98985376
题意:有1-n n个能量石头,每个石头有初始值E_i,每个单位时间增加L_i值,上限为C_i值,m次操作,每次在时间ti,选择区间[l,r]的石头并获取它们的能量,获取后石头的能量为0。问最后获取了多少能量。
题解:
考虑每个石头对答案的贡献, 首先要算出来每个石头能量集满要多长时间 d.
然后要统计每个石头询问的时间差,
时间差 >= d, 加上 c. 统计个数 直接 * c,
时间差 < d, 加上 时间差*l[i].统计所有的时间和 * l.
然后还要计算一下初始状态. e.随便搞搞就好了.
然后我们如何维护时间差呢?

用 set + 树状数组维护, 
每次把时间点加入到 set 中, 就会有可能减少一个时间段,加上两个小的时间段,
然后我们用树状数组维护时间段. 
两个树状数组分别维护
1.每个时间段的个数. 求 >= d 一共有多少个时间段.
2.每个时间段一共有多少时间. 求 < d 一共有多少时间,

要注意除0 的情况.
代码:

#include
using namespace std;
const int maxn=100010;
const int maxT=200010;//--
#define inf 0x3f3f3f3f
#define ll long long
 
 
namespace BIT{
    ll sum[maxT],sum2[maxT];
    int n;
    void init(int _n){
        n=_n;
        for(int i=0;i<=n;i++) sum[i]=0,sum2[i]=0;
        //memset(sum,0,sizeof(sum));memset(sum2,sizeof(sum2));
    }
    int lowbit(int x){
        return x&(-x);
    }
    void Add1(int x,ll val){//
        for(;x<=n;sum[x]+=val,x+=lowbit(x));
    }
    ll getsum1(int x){
        ll res=0;
        for(;x>0;res+=sum[x],x-=lowbit(x));
        return res;
    }
     
    void Add2(int x,ll val){//
        for(;x<=n;sum2[x]+=val,x+=lowbit(x));
    }
    ll getsum2(int x){
        ll res=0;
        for(;x>0;res+=sum2[x],x-=lowbit(x));
        return res;
    }
};
 
vector<int> f[maxn],g[maxn];
int e[maxn],l[maxn],c[maxn],d[maxn];
set<int> st;
int n,m;
int main()
{
    int tt,cas=1;
    scanf("%d",&tt);
    while(tt--){
        scanf("%d",&n);
        int mx=0;
        for(int i=1;i<=n;i++) f[i].clear(),g[i].clear();
        for(int i=1;i<=n;i++){
            scanf("%d%d%d",&e[i],&l[i],&c[i]);
            if(l[i]==0||c[i]==0) d[i]=0;
            else d[i]=(c[i]-1)/l[i]+1;
            mx=max(mx,d[i]);//---
        }
        int a,b,t;
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&t,&a,&b);
            f[a].push_back(t);
            g[b].push_back(t);
            mx=max(mx,t);
        }
        ll ans=0;
        int num=0;//number of left binary
        st.clear();
        BIT::init(mx);//
        set<int>::iterator it;//
        for(int i=1;i<=n;i++){
            for(int j=0;j<(int)f[i].size();j++){
                num++;
                int cur=f[i][j];
                if(st.size()==0){
                    st.insert(cur);continue;
                }
                //auto it=st.lower_bound(cur);
                it=st.lower_bound(cur);
                if(it==st.begin()){
                    int now=(*it)-cur;
                    BIT::Add1(now,now);
                    BIT::Add2(now,1);
                }else if(it==st.end()){
                    it--;
                    int now1=cur-(*it);
                    BIT::Add1(now1,now1);
                    BIT::Add2(now1,1);
                }else{
                    int now=(*it);it--;
                    int now1=(*it);
                    BIT::Add1(now-cur,now-cur);
                    BIT::Add1(cur-now1,cur-now1);
                    BIT::Add1(now-now1,-(now-now1));
                    BIT::Add2(now-cur,1);
                    BIT::Add2(cur-now1,1);
                    BIT::Add2(now-now1,-1);
                }
                st.insert(cur);
            }
            ll ans1=1LL*(num-1-BIT::getsum2(d[i]-1))*c[i];
            ll ans2=1LL*BIT::getsum1(d[i]-1)*l[i];
            ll ans3=min(1LL*c[i],1LL*e[i]+1LL*l[i]*(*st.begin()));
            if(num){
                if(!d[i]) ans+=e[i];
                else ans+=ans1+ans2+ans3;
            }
            for(int j=0;j<(int)g[i].size();j++){
                num--;
                int cur=g[i][j];
                //auto it=st.find(cur);
                it=st.find(cur);
                if((int)st.size()==1){
                    st.erase(cur);continue;// erase(cur) not erase(it)!!
                }
                if(it==st.begin()){
                    it++;
                    int now=(*it)-cur;
                    BIT::Add1(now,-now);
                    BIT::Add2(now,-1);
                     
                }else{
                    it++;
                    if(it==st.end()){
                        it--;it--;
                        int now1=cur-(*it);
                        BIT::Add1(now1,-now1);
                        BIT::Add2(now1,-1);
                    }else{
                        int now=(*it);
                        it--;it--;
                        int now1=(*it);
                        BIT::Add1(now-cur,-(now-cur));
                        BIT::Add1(cur-now1,-(cur-now1));
                        BIT::Add1(now-now1,now-now1);
                        BIT::Add2(now-cur,-1);
                        BIT::Add2(cur-now1,-1);
                        BIT::Add2(now-now1,1);
                    }
                     
                }
                st.erase(cur);//
            }
        }
        printf("Case #%d: %lld\n",cas++,ans);
    }
    return 0;
}

H Pair

题意:给定A B C(1,1e9),求对数(x,y),使得 1 < = x < = A , 1 < = y < = B 1<=x<=A,1<=y<=B 1<=x<=A,1<=y<=B,且满足x&y>C||x^y 题解:数位dp

#include
using namespace std;
#define ll long long
const int maxn=100010;


ll dp[100][2][2][2][2];
int a[33],b[33],c[33];
//fa 当前的数是否已小于a,fb同理
//h1 是否已满足x&y<=C  h2是否已满足x^y>=C
ll dfs(int x,int fa,int fb,int h1,int h2)
{
	if(x==-1) return 1;
	ll res=dp[x][fa][fb][h1][h2];//
	if(res!=-1) return res;
	res=0;
	for(int i=0;i<=(fa?1:a[x]);i++){
		for(int j=0;j<=(fb?1:b[x]);j++){
			if((!h1)&&((i&j)>c[x])) continue;//如果当前位x_i&y_i已大于c_i,那么x&y>c 不满足条件
			if((!h2)&&((i^j)<c[x])) continue;//同理
			res+=dfs(x-1,fa||(i<a[x]),fb||(j<b[x]),h1||(i&j)<c[x],h2||(i^j)>c[x]);//后面这里不能取等于号噢 
		}
	}
	return dp[x][fa][fb][h1][h2]=res;
}
void pre(int a[],int x)
{
	for(int i=30;i>=0;i--)
		if(x&(1<<i)) a[i]=1;
		else a[i]=0;
}
void print(int a[])
{
	printf("------------\n");
	for(int i=30;i>=0;i--){
		printf("%d",a[i]);
	}
	printf("\n");
}
int main()
{
	int t;scanf("%d",&t);
	while(t--){
		int A,B,C;
		memset(dp,-1,sizeof(dp));
		scanf("%d%d%d",&A,&B,&C);
		pre(a,A);
		pre(b,B);
		pre(c,C);
		//print(a);print(b);print(c);
		ll ans=dfs(30,0,0,0,0);
		ans-=max(0,B-C+1);//去掉A取0的情况 
		ans-=max(0,A-C+1);// 去掉B取0的情况 
		printf("%lld\n",1LL*A*B-ans); 
	}
	return 0;
}

对于是否为0,可以再加两个位置判断下

#include
using namespace std;
#define ll long long
const int maxn=100010;


ll dp[100][2][2][2][2][2][2];
int a[33],b[33],c[33];
//fa 当前的数是否已小于a,fb同理
//h1 是否已满足x&y<=C  h2是否已满足x^y>=C
ll dfs(int x,int fa,int fb,int h1,int h2,int cura,int curb)
{
	if(x==-1){
		if(cura&&curb) return 1;
		return 0;
	}
	ll &res=dp[x][fa][fb][h1][h2][cura][curb];//
	if(res!=-1) return res;
	res=0;
	for(int i=0;i<=(fa?1:a[x]);i++){
		for(int j=0;j<=(fb?1:b[x]);j++){
			if((!h1)&&((i&j)>c[x])) continue;//如果当前位x_i&y_i已大于c_i,那么x&y>c 不满足条件
			if((!h2)&&((i^j)<c[x])) continue;//同理
			res+=dfs(x-1,fa||(i<a[x]),fb||(j<b[x]),h1||(i&j)<c[x],h2||(i^j)>c[x],cura||i,curb||j);
		}
	}
	return res;
}
void pre(int a[],int x)
{
	for(int i=30;i>=0;i--)
		if(x&(1<<i)) a[i]=1;
		else a[i]=0;
}
void print(int a[])
{
	printf("------------\n");
	for(int i=30;i>=0;i--){
		printf("%d",a[i]);
	}
	printf("\n");
}
int main()
{
	int t;scanf("%d",&t);
	while(t--){
		int A,B,C;
		memset(dp,-1,sizeof(dp));
		scanf("%d%d%d",&A,&B,&C);
		pre(a,A);
		pre(b,B);
		pre(c,C);
		//print(a);print(b);print(c);
		ll ans=dfs(30,0,0,0,0,0,0);
		
		printf("%lld\n",1LL*A*B-ans); 
	}
	return 0;
}

I Chessboard

题意:给定n m,构造kk的矩阵,该矩阵的每个元素值不小于m,使得选择任意不同行、不同列的k个元素的总和都相等,且不大于n
官方题解:
2019牛客暑期多校训练营(第七场)_第1张图片
容易证明,一个 k
k 棋盘的排布方案满足“不同行不同列的方格内的玻璃球数量的总和均相
同”要求,当且仅当该方案具有如下形式:
∑ i = 1 k a i A i + ∑ i = 1 k b i B i \sum_{i=1}^{k} a_iAi +\sum_{i=1}^{k} b_iB_i i=1kaiAi+i=1kbiBi/,其中 A i ( B i ) A_i(B_i) Ai(Bi)为第i行(列)均为1,其余行(列)均为0的k*k矩阵,又因为该和为T,所以$ a i 和 a_i和 aib_i$需满足以下条件:
∑ i = 1 k a i + ∑ i = 1 k = T ( a i ≥ 0 , b i ≥ 0 ) \sum_{i=1}^{k} a_i +\sum_{i=1}^{k} = T (a_i\geq0,b_i\geq0) i=1kai+i=1k=T(ai0,bi0),用隔板法思想,得到满足该条件的方案为 C T + 2 k − 1 2 k − 1 C_{T+2k-1}^{2k-1} CT+2k12k1
但是这些方案中其实有一部分是重复的。重复的原因在于:当 a i a_i ai均为非负时,事实上此时将所有 a i a_i ai全部减一,将所有 b i b_i bi全部加一,,将得到一种完全相同的、但我们也记了一次数的方案。我们应该想办法将这种方案全部去除并只留下这种方案的唯一代表。很显然,我们只需要再减去满足:
∑ i = 1 k a i + ∑ i = 1 k = T ( a i ≥ 1 , b i ≥ 0 ) \sum_{i=1}^{k} a_i +\sum_{i=1}^{k} = T (a_i\geq1,b_i\geq0) i=1kai+i=1k=T(ai1,bi0)
的方案数即可。因此所有的方案数即为
C T + 2 k − 1 2 k − 1 − C T + k − 1 2 k − 1 C_{T+2k-1}^{2k-1} -C_{T+k-1}^{2k-1} CT+2k12k1CT+k12k1

#include
using namespace std;
const int maxn=6010; 
#define inf 0x3f3f3f3f
#define ll long long
const int mod=998244353;

int f[maxn],invf[maxn];
ll quickp(ll a,ll p)
{
	ll res=1;
	while(p){
		if(p&1) res=res*a%mod;
		p>>=1;
		a=a*a%mod;
	}
	return res;
}
void init()
{
	invf[0]=f[0]=1;
	for(int i=1;i<maxn;i++) f[i]=1LL*i*f[i-1]%mod;
	invf[maxn-1]=quickp(f[maxn-1],mod-2);
	for(int i=maxn-2;i>=1;i--) invf[i]=1LL*invf[i+1]*(i+1)%mod;
}
//开这个爆内存了。。 
//int C[maxn][maxn];
//void init()
//{
//	C[0][0]=1;
//	for(int i=1;i
//		C[i][0]=1;
//		for(int j=1;j<=i;j++){
//			C[i][i-j]=C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
//		}
//	}
//}
ll C(ll x,ll y)
{
	if(y>x) return 0;
	return 1LL*f[x]*invf[y]%mod*invf[x-y]%mod; 
}
void Add(ll &x,ll y)
{
	x+=y;
	if(x>=mod) x-=mod;
}
void Sub(ll &x,ll y)
{
	x-=y;
	if(x<0) x+=mod;
}
int n,m;
int main()
{
	int tt;scanf("%d",&tt);
	init();
	while(tt--){
		scanf("%d%d",&n,&m);
		ll ans=0;
		for(int k=1;k*m<=n;k++){
			for(int t=0;t<=n-k*m;t++){
				Add(ans,C(t+2*k-1,2*k-1));
				Sub(ans,C(t+k-1,2*k-1));
			}
		}
		printf("%lld\n",ans);
	}
	return 0;
}

J A+B problem

求A和Breverse后相加的结果,队友AC代码

#include
#define LL long long
#define ms0(x) memset(x,0,sizeof(x))
#define ms-1(x) memset(x,-1,sizeof(x))
LL a,b;using namespace std;
void change(LL &a)
{
    string tmp;
    stringstream ss;
    ss<<a;
    ss>>tmp;
    reverse(tmp.begin(),tmp.end());
    ss.clear();
    ss<<tmp;
    ss>>a;
    return;
}
 
int main()
{
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--)
    {
        cin>>a>>b;
        change(a);
        change(b);
        LL c;
        c=a+b;
        change(c);
        cout<<c<<endl;
    }
    return 0;
}

你可能感兴趣的:(集训)