eg:這場似乎比較簡單。E題賽後補的,似乎是區間dp比較簡單的題(之前完全沒學過區間dp呢),B和C真是交的慢了,不然rk能往上升升的。
傳送門
A
題意:判斷A能否整除B
#include "stdio.h"
#include "string.h"
#include "string"
#include "iostream"
#include "algorithm"
#include "vector"
#include "queue"
#include "math.h"
#include "map"
#include "stack"
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const ll INF=1e12;
const double eps=1e-6;
int n,m;
int main(){
int T;
scanf("%d",&T);
while(T--){
int a,b;
scanf("%d%d",&a,&b);
if(a%b==0)puts("YES");
else puts("NO");
}
return 0;
}
B
題意:給出一個數組進行重排,問怎麼排使得不存在相等。
題解:從大到小輸出即可。
#include "stdio.h"
#include "string.h"
#include "string"
#include "iostream"
#include "algorithm"
#include "vector"
#include "queue"
#include "math.h"
#include "map"
#include "stack"
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const ll INF=1e12;
const double eps=1e-6;
int n,m,a[maxn];
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
sort(a+1,a+1+n);
for(int i=n;i>1;i--)printf("%d ",a[i]);
printf("%d\n",a[1]);
}
return 0;
}
C
題意:給出n個數字的數組a和一個全0的數組,每一輪操作i可以使得全0數組的任意一個位置加上,問是否可以把全0數組變成數組a。
題解:將所有數字轉換成相應的k進制數,保證每一位要麼是1要麼是0,並且同一位置最多隻有一個1。
#include "stdio.h"
#include "string.h"
#include "string"
#include "iostream"
#include "algorithm"
#include "vector"
#include "queue"
#include "math.h"
#include "map"
#include "stack"
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const ll INF=1e12;
const double eps=1e-6;
int n,m;
ll k;
ll vvis[110],vis[80];
ll a[maxn];
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%lld",&n,&k);
memset(vvis,0,sizeof(vvis));
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
int flag=1;
for(int i=1;i<=n;i++){
if(a[i]==0)continue;
else{
ll t=a[i];
int x=0;
memset(vis,0,sizeof(vis));
while(t){
vis[x]=t%k;
t/=k;
x++;
}
for(int i=0;i<=x;i++)
if(vis[i]==1){
if(vvis[i]==1)flag=0;
else vvis[i]=1;
}else if(vis[i]!=0)flag=0;
}
}
if(flag)puts("YES");
else puts("NO");
}
return 0;
}
D
題意:給出n個位置和m個數字(1~m),保證這n個位置最多隻有兩個數字是一樣的,並且保證安排後的數組是先單調遞增後單調遞減的,問最多有多少種安排的方式。
題解:枚舉最大數字i,那麼就是從剩下的數字裏面挑出n-2個數字,接着從挑出來的數字裏選擇一個數字是相等的,最後就是對這n-3個數字進行位置排列,答案即爲
#include "stdio.h"
#include "string.h"
#include "string"
#include "iostream"
#include "algorithm"
#include "vector"
#include "queue"
#include "math.h"
#include "map"
#include "stack"
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
const ll mod=998244353;
const int inf=0x3f3f3f3f;
const ll INF=1e12;
const double eps=1e-6;
ll f[maxn],jc[maxn];
ll quick(ll a,ll b){
ll res=1;
while(b){
if(b&1)res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll C(ll n,ll m){
return f[n]*quick(f[m]*f[n-m]%mod,mod-2)%mod;
}
int main(){
f[0]=1;jc[0]=1;
for(ll i=1;i<=200000;i++)
f[i]=f[i-1]*i%mod,jc[i]=jc[i-1]*2%mod;
ll n,m;
scanf("%lld%lld",&n,&m);
ll ans=0;
for(ll i=n-1;i<=m;i++){
ll t=C(i-1,n-2)%mod;
t=t*C(n-2,1)%mod;
t=t*jc[n-3]%mod;
ans=(ans+t)%mod;
}
printf("%lld\n",ans);
return 0;
}
E
題意:給出一個數組a,每次可以選擇數組裏相等的兩個相鄰數字合併成,問若干次後,數組剩下的長度是多少。
題解:區間dp的題目。感覺很先進。枚舉區間長度len,接着枚舉起點i,最後枚舉這個區間[i,i+len-1]的分割點k,那麼區間的答案就應該是分割的兩個區間之和。考慮特殊情況會產生合併,如果兩個區間的長度都爲1且數值相等,就代表可以合併。最後答案就是dp[1][n]。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
int n,a[510],dp[510][510],f[510][510];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
dp[i][i]=1,f[i][i]=a[i];
for(int len=2;len<=n;len++){
for(int i=1;i<=n-len+1;i++){
int j=i+len-1;
dp[i][j]=INF;
for(int k=i;k<=j-1;k++){
if(dp[i][j]>=dp[i][k]+dp[k+1][j]){
dp[i][j]=dp[i][k]+dp[k+1][j];
if(dp[i][k]==1 && dp[k+1][j]==1 && f[i][k]==f[k+1][j]){
dp[i][j]=1;
f[i][j]=f[i][k]+1;
}
}
}
}
}
printf("%d\n",dp[1][n]);
return 0;
}