iwtgm-24

A.

考虑按块来计算
如果这个块在两边,那么除了与这个块相邻的那一个数与这个块的数不同(一个块里的数都是一样的),其他位置上的数任选
若这个块在中间,那么与这个块相邻的左右两个数与这个块的数不同,其他位置上的数任选
块的大小从1-n,每个块可选数字为10种,相邻数可选数字为9种,其他位置可选10种

ll n,pw[N];
int main(){
	cin>>n,pw[0]=1;
	for(int i=1;i<=n;i++)pw[i]=pw[i-1]*10%mod;
	for(int i=1;i<=n;i++){
		if(i==n)puts("10");
		else cout<<(pw[n-i]*18+(n-i-1)*pw[n-i-1]*81)%mod<<" ";
	}
	return 0;
}

B.

提炼本质,打破所给题意限制的好题
题目说数组a非降序,数组b非递增,但这只是数组位置的要求
数组里的元素可以由其他方式得到和计算,最后按要求放进数组即可
我们把数组元素全拿出来
据题意,易得数组a的最大值小于b的最小值,那么也就是由2m个数组成一个非降序(相当于把b数组反转,也就成了非递增)
也就是说,值域是1-n,数量是2m,可重复取,组成一个非降序有多少种方式
如此考虑:有n个盒子,编号为1-n,然后我们把2m个小球扔向这n个盒子,最后我们从1-n遍历,第i个盒子里有几个小球就把几个盒子编号放入序列,易得这一定是非降序的
再想:我们把每个盒子都放入一个球,也就是现在小球数量有2m+n个,那么就有2m+n-1个空隙,选出n-1个空隙把它们分成n份,至此问题解决

ll fac[N],inv[N];//阶乘数组,阶乘的逆元数组
const ll mod=1e9+7;//是质数的模数
ll power(ll x,ll y){//快速幂
    ll ans=1;
    while(y){
        if(y&1)ans=ans*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return ans;
}
void init(){
    fac[0]=1;//0的阶乘是1
    inv[0]=power(1,mod-2);//1的逆元
    for(ll i=1;i<N;i++){
        fac[i]=i*fac[i-1]%mod;//递推求阶乘
        inv[i]= power(fac[i],mod-2);//递推求阶乘的逆元
    }
}
ll C(ll x,ll y){
    if(x<y)return 0;//c下方的数比上方的数大,否则不合法
    return fac[x]*inv[y]%mod*inv[x-y]%mod;//把除法变成逆元的乘法
}

void solve() {
    int n,m;cin>>n>>m;
    init();
    cout<<C(2*m+n-1,n-1);
}

再来一个用dp解的
dp[i][j],i表示第几个数,j代表这个数取什么
dp[k][i]=(dp[k-1][i]+dp[k][i-1])%mod;枚举j,因为满足非降序,可以跟前一个数取的一样,也可以由当前数j-1转移而来(当前能取j-1那么一定能取j,同样满足非降序。这个dp转移非常好。
dp[m][i]*dp[m][n-j+1]就是a,b数组第m位能取值的所有情况

const int mod=1e9+7;
const int ma=1001;
int n,m;
ll dp[22][ma];
void solve() {
    cin>>n>>m;
    for(int i=1;i<=n;i++)dp[1][i]=1;
    for(int k=2;k<=m;k++){
        for(int i=1;i<=n;i++){
            dp[k][i]=(dp[k-1][i]+dp[k][i-1])%mod;
        }
    }
    ll ans=0;
    for(int i=1;i<=n;i++){
        for(int j=i;j<=n;j++){
            ans=(ans+(dp[m][i]*dp[m][n-j+1])%mod)%mod;
        }
    }
    cout<<ans<<endl;
}

C.

这样想:当第i个格子是有威胁的,那么它的花费是3,因为我先走过它去解除威胁,再跑回去接士兵,再走过这个格子
第i个格子没有威胁,花费是1,我直接带着士兵走
用差分做,陷阱+1,机关-1,当前缀和为0时花费为1,不为0花费为3

int m,n,k,t;
int a[N];
int l[N],r[N],d[N],vi[N];
bool check(int x){
    int jd=a[x];
    for(int i=1;i<=k;i++){
        if(d[i]>jd){
            vi[l[i]]++;
            vi[r[i]+1]--;
        }
    }
    int sum=0;
    for(int i=1;i<=n+1;i++){
        vi[i]=vi[i]+vi[i-1];
        if(vi[i]!=0)sum+=3;
        else sum+=1;
    }
    if(sum<=t)return 1;
    return 0;
}
bool cmp(int x,int y){
    return x>y;
}
void solve() {
    cin>>m>>n>>k>>t;
    for(int i=1;i<=m;i++)cin>>a[i];
    for(int i=1;i<=k;i++)cin>>l[i]>>r[i]>>d[i];
    sort(a+1,a+1+m,cmp);
    int l_=1,r_=m,mid;
    int ans=0;
    while(l_<=r_){
        mid=(l_+r_)/2;
        memset(vi,0,sizeof(vi));
        if(check(mid)){
            ans=max(mid,ans);
            l_=mid+1;
        }else r_=mid-1;
    }
    cout<<ans<<endl;
}
posted @ 2023-11-23 21:19  WW爆米花  阅读(3)  评论(0编辑  收藏  举报