题意: 给出一个长度为n的数组,要求构造一个数组相邻k个数的和相同
题解: 用set存放出现的数字,如果多于k就不能构造,否则就n*k构造即可,挺水的一道题然后突然被自己蠢到了。(掉分┭┮﹏┭┮)
#include
#include
#include
#include
#include
using namespace std ;
typedef long long ll ;
const int N = 1e5+10 ;
int n,k,x ;
set<int> st ;
int main(){
int t; scanf("%d",&t) ;
while(t--){
st.clear() ;
scanf("%d%d",&n,&k) ;
for(int i=0 ; i<n ; ++i) scanf("%d",&x) ,st.insert(x) ;
if(st.size() > k){
printf("-1\n") ;
continue ;
}
for(int i=1 ; st.size()<k ; ++i) st.insert(i) ;
printf("%d\n",n*k) ;
for(int j=0 ; j<n ; ++j)
for(set<int>::iterator it=st.begin() ; it!=st.end() ; ++it) printf("%d ",*it) ;
printf("\n") ;
}
return 0 ;
}
题意: 给出一个长度字符串,要求分成k份,问分成的字符串中字典序最大的最小值是哪个字符串。
题解 先将字符串排序,要使得字典序变小前面尽量放小的,前k个数各取一个作为头,①、如果s[1]!=s[k]那就直接输出s[k],因为后面的字符和s[k]前面的组合一定比s[k]小,如果s[k]后面解字符肯定比单个s[k]大,②、如果s[k+1]!=s[n]说明,那么就直接输出s[k]和后面的,例如:n=5,k=2,排列后:aabbc,那先取各a为头,后面一个a解后面全部字符,就是 a abbc(最大为abbc) ,如果分一个到前面就是ab abc(最大为abc),或者ac abb(最大为ac),其中最大值的大小排列为(ac > abc > abbc),最后如果都不属于上面的情况就每隔k位输出即可。
这道题比较考察分析,(脑子越分析越乱,本来一开始倒是有点知道怎么做,越想越不会)
#include
#include
#include
using namespace std ;
typedef long long ll ;
const int N = 1e5+10 ;
char s[N] ;
int n,k ;
void solve(){
if(s[1]!=s[k]){
putchar(s[k]) ;
return ;
}
if(s[k+1]!=s[n]){
putchar(s[1]) ;
for(int i=k+1 ; i<=n ; ++i) putchar(s[i]) ;
return ;
}
for(int i=1 ; i<=n ; i+=k) putchar(s[i]) ;
}
int main(){
int t; scanf("%d",&t) ;
while(t--){
scanf("%d%d",&n,&k) ;
scanf("%s",s+1) ;
sort(s+1,s+n+1) ;
solve() ;
putchar('\n') ;
}
return 0 ;
}
题意: 每个细菌可以在白天的时候分裂,当一个细菌分裂成两个细菌时,子细菌的质量为母细菌的一半,晚上的时候,每个细菌的质量自增1,第一天会有一个质量为1的细菌。现要得到总质量为n的细菌,问最少几天能得到,并说明这几天内,每天分裂的细菌数。
题解: 若当天有x个细菌,那么晚上就会增加x的质量,如果白天分裂i个细菌,总细菌变成2*i+(x-i)=x+i,那么晚上就会增加x+i的质量。
要最少天数达到n,那么就尽量一直全部分裂,那么每一晚的增量就是2 , 4 ,8,16 ……,先找到最接近n的总和,比如1+2+4=7<10 , 然后多出来的3,就相当于其中有一天是增加3,那这个增加的3是在哪一天增加的呢,细菌数是直线上升的,所以3只能在2和4之间出现,所以增加的质量为:1 2 3 4 ,表示1 分裂成2个细菌,2个细菌分裂成3个细菌(即中间只有一个细菌分裂),3个细菌分裂成4个细菌(中间有一个细菌分裂),所以每天有几个细菌分裂就是这个增值的差值。
可以再用n=12来举例: 1+2+4=7<12 , 12-7=5 , 所以增量数组为:1 2 4 5 ,
1分裂成2(一个细菌分裂),2分裂成4(两个细菌分裂),4分裂成5(一个细菌分裂)。
感觉这道题还是蛮有意思的,直接从增量方面考虑(好题~~)
#include
#include
#include
#include
using namespace std ;
typedef long long ll ;
const int N = 1e5+10 ;
vector<int> v ;
int n,k ;
int main(){
int t; scanf("%d",&t) ;
while(t--){
v.clear() ;
int n ; scanf("%d",&n) ;
int sum=0 ;
for(int i=1 ; sum+i<=n ; i<<=1){
sum += i ;
v.push_back(i) ;
}
if(sum<n) v.push_back(n-sum) ;
sort(v.begin(),v.end()) ;
printf("%d\n",v.size()-1) ;
for(int i=1 ; i<v.size() ; ++i) printf("%d ",v[i]-v[i-1]) ;
printf("\n") ;
}
return 0 ;
}
题意: 给出n颗树,还有n颗树上红果和蓝果的数量,每个篮放满需要k个果子,放在同一个篮子的果子必须是同种颜色或者是同一棵树上的果子,问最多能放满几个篮子。
题解: 用dp[i][j] 表示前i颗树上剩余j个红果子能放满的篮子数量,然后蓝果子的剩余数量为:总数量-篮子数量*k-红果子数量(bres=sum-dp[i][j]*k-j),处理当前树时可以看做:同色果子篮子数个+一个同树果子篮子,前面取整除即可,后面就可以枚举同一颗树上红果和蓝果数量,用s1表示放在同树果子篮子的红果数量,那么该篮子放蓝果为k-s1 , 除去这些加上本颗树的果子,红果子的数量为:本颗树红果数+上一颗树剩余数量-放在同树果篮子的数量(a[i]+j-s1), 蓝果子为:本颗树蓝果数量+蓝果剩余数-放在同树果子篮子数(b[i]+bres-(k-s1))
还有个很玄学的点就是,一开始全部数的类型都是long long,然后TLE了,后来只有sum、dp、mx是long long就能过了(迷惑.jpg),原来数据类型也是会影响运行时间的。
#include
#include
#include
using namespace std ;
typedef long long ll ;
const int N = 510 ;
ll dp[N][N];
int a[N] , b[N] ;
int main(){
int n,k ; scanf("%d%d",&n,&k) ;
for(int i=1 ; i<=n ; ++i) scanf("%d%d",&a[i],&b[i]) ;
memset(dp,-1,sizeof(dp)) ;
dp[0][0]=0 ;
ll sum=0 ;
int anum,bnum;
for(int i=1 ; i<=n ; ++i){
for(int j=0 ; j<k ; ++j){
if(dp[i-1][j]==-1) continue ; //前i-1颗树不存在剩余j的情况就跳过
ll bres=sum-dp[i-1][j]*k-j ; //前i-1颗树装完之后剩余的蓝果数
for(ll s1=1 ; s1<=a[i]&&s1<k ; ++s1){
if(b[i]+s1>=k){
anum=a[i]+j-s1 ; //除去放在不同色篮子的红果数
bnum=b[i]+bres-(k-s1) ;
dp[i][anum%k] = max(dp[i][anum%k],dp[i-1][j]+anum/k+bnum/k+1) ;
}
}
anum=a[i]+j , bnum=b[i]+bres ; //同一颗树不同色不放在同一个篮子的果子数
dp[i][anum%k] = max(dp[i][anum%k],dp[i-1][j]+anum/k+bnum/k) ;
}
sum += a[i]+b[i] ;
}
ll mx=0 ;
for(int i=1 ; i<=n ; ++i){
for(int j=0 ; j<=k ; ++j)
mx = max(mx,dp[i][j]) ;
}
printf ("%lld\n",mx) ;
return 0 ;
}
本次比赛总结:太菜了(掉分了┭┮﹏┭┮)