官方题解:2015 Multi-University Training Contest 4 solutions BY 学军中学
1001
题意:每次询问\([a,b](a\leqslant b)\)中有多少个 beautiful number, beautiful number指每位数字不同
\( 1\leqslant T\leqslant 1000,1\leqslant a\leqslant b\leqslant 10^5\)
因为范围比较小,可以直接暴力预处理出[1,n]内beautiful number的数量。
[a,b]=[1,a]-[1,b-1]
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<string>
using namespace std;
#define MAX(a,b) ((a>b)?(a):(b))
#define MIN(a,b) ((a<b)?(a):(b))
#define LL __int64
#define N 100005
#define INF 1<<30
int cnt[N];
int vis[10];
void init(){
memset(cnt,0,sizeof(cnt));
int t,flag;
for(int i=1;i<=100000;++i){
t=i;
flag=0;
memset(vis,0,sizeof(vis));
while(t){
vis[t%10]++;
if(vis[t%10]>1){
flag=1;
break;
}
t/=10;
}
cnt[i]=cnt[i-1];
if(flag==0)
cnt[i]++;
}
}
int main(){
int T;
scanf("%d",&T);
init();
while(T--){
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",cnt[b]-cnt[a-1]);
}
return 0;
}
1002
题意:求出最长的等差数列和等比数列,答案取两者长度大的
\(1\leqslant n\leqslant 10^6\)
随便YY一发就能过。
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<string>
using namespace std;
#define MAX(a,b) ((a>b)?(a):(b))
#define MIN(a,b) ((a<b)?(a):(b))
#define INF 0x3f3f3f3f
#define ll __int64
#define N 1000010
int n;
int a[N];
int dp[N][2];
int main()
{
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
dp[1][0]=dp[1][1]=1;
for(int i=2;i<=n;i++) dp[i][0]=dp[i][1]=2;
for(int i=3;i<=n;i++){
if(a[i]-a[i-1]==a[i-1]-a[i-2]) dp[i][0]=dp[i-1][0]+1;
if(a[i]*1.0/a[i-1]==a[i-1]*1.0/a[i-2]) dp[i][1]=dp[i-1][1]+1;
}
int ans=0;
for(int i=1;i<=n;i++){
ans=max(ans,max(dp[i][0],dp[i][1]));
}
printf("%d\n",ans);
}
return 0;
}
1007
题意:知道一个序列的不同的连续字串个数K,求构造满足K的任意一个序列
\(1\leqslant K\leqslant 10^9\),序列长度\(1\leqslant K\leqslant 10^5\)
因为序列长度\(n\)的最大范围小于\(K\),所以不能用全填\(1\)的方法
如果序列为这种形式:\(1,\cdots ,1,2\cdots,2,3,\cdots,3,\cdots,t\)
设\(n\)为序列长度,\(L_i\)为数\(i\)出现的次数,那么序列的不同的连续字串个数
$$K=\frac{n^2+n-\sum_{i=1}^{t}L_i(L_i-1)}{2}$$
可以列出下面的方程
\sum_{i=1}^{t}L_i(L_i-1)=n^2+n-2k\\
\sum_{i=1}^{t}L_i=n
\end{matrix}\right.$$
设\(\sum_{i=1}^{t}L_i(L_i-1)=d\),那么可以用二分找出最大的\(p\)使\(p(p-1)\leqslant d\),然后\(L_1\)可以取\(p\)
此时另\(d=d-p(p-1)\),又可以用上面的方法求出所有\(L_i\)。因为\(d\)一定为偶数,所以最后一定能让\(d=0\)
因为\(d=n^2+n-2k\),所以需要用二分找到最小的\(n\)满足\(n^2+n-2k\geqslant 0\)
如果最后满足 \(\sum_{i=1}^{t}L_i=n \),那么便是一个解。
通过打表发现不满足的只有\(k=4\)和\(k=16\)时,对于这两组直接全输出1就行
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<string>
using namespace std;
#define MAX(a,b) ((a>b)?(a):(b))
#define MIN(a,b) ((a<b)?(a):(b))
#define LL __int64
#define N 100005
#define INF 1<<30
int L[N];
int cnt;
int main(){
LL k;
LL n;
while(~scanf("%I64d",&k)){
cnt=0;
if(k==4||k==16){
printf("%d\n",k);
while(k--){
printf("1");
if(k!=0)printf(" ");
}
printf("\n");
continue;
}
//cal min(n) :n^2+n-2k>=0
LL l=1,r=100000,m;
while(l<=r){
m=(l+r)>>1;
if(m*m+m-2*k>=0){
n=m;
r=m-1;
}else{
l=m+1;
}
}
//cal L[]
LL d=n*n+n-2*k;
LL p;
LL len=0;
while(d||len<n){
l=1,r=100000;
while(l<=r){
m=(l+r)>>1;
if(m*(m-1)<=d){
p=m;
l=m+1;
}else{
r=m-1;
}
}
if(p==0)p=1;
L[++cnt]=(p?p:1);
len+=p;
d=d-p*(p-1);
}
printf("%I64d\n",n);
int first=true;
for(int i=1;i<=cnt;++i){
n-=L[i];
while(L[i]--){
if(!first)printf(" ");
printf("%d",i);
first=false;
}
}
printf("\n");
}
return 0;
}
1010
题意:在一个c*r的格子里,有一些水滴。一个大小大于4的水滴会向4个方向(上下左右)分裂成4个小水滴。小水滴会一直沿分裂方向运动,直到遇到水滴,使水滴大小加1,小水滴消失。现在给出一些水滴的坐标和大小。并在0s时在(x,y)处有一个水滴分裂。问Ts时所有水滴的状态
\( 1\leqslant r \leqslant100, 1\leqslant c\leqslant 100, 1\leqslant n\leqslant 100, 1\leqslant T\leqslant 10000 \)
因为数据范围较小,可以直接模拟整个过程。
有三点需要注意:
1、无论分裂前的水滴大小是多少,分裂后小水滴的大小始终是为1的。
2、0s时注意判断是否有水滴大小大于4,这些水滴在0s分裂。
3、水滴分裂后及时清除水滴的标记,此时水滴已经不存在
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<string>
using namespace std;
#define MAX(a,b) ((a>b)?(a):(b))
#define MIN(a,b) ((a<b)?(a):(b))
#define LL __int64
#define N 105
#define INF 1<<30
struct node1 {
int x,y;
node1() {}
node1(int _x,int _y) {
x=_x;
y=_y;
}
} wd[N];
struct node2 {
int x,y,d;
node2() {}
node2(int _x,int _y,int _d) {
x=_x;
y=_y;
d=_d;
}
};
int mpt[N][N];
int val[N][N];
int dir[4][2]= {0,1,1,0,0,-1,-1,0};
int ans[N];
int r,c,n,T;
queue<node2> sd;
vector<node2> temp;
void init() {
memset(mpt,0,sizeof(mpt));
memset(val,0,sizeof(val));
memset(ans,-1,sizeof(ans));
while(!sd.empty())sd.pop();
temp.clear();
}
//判断是否超出边界
bool judge(node2 a) {
if(a.x<1||a.x>r||a.y<1||a.y>c)return false;
return true;
}
//判断当前位置是否为水滴
bool iswd(node2 a) {
if(mpt[a.x][a.y])return true;
return false;
}
//水滴分裂
void crack(int t) {
for(int i=1; i<=n; ++i) {
if(val[wd[i].x][wd[i].y]>4&&mpt[wd[i].x][wd[i].y]) {
ans[i]=t;
for(int j=0; j<4; ++j)
temp.push_back(node2(wd[i].x,wd[i].y,j));
val[wd[i].x][wd[i].y]=4;
mpt[wd[i].x][wd[i].y]=0;
}
}
for(int i=0; i<temp.size(); ++i)
sd.push(temp[i]);
temp.clear();
}
//模拟
void bfs(int sx,int sy) {
node2 now,next;
for(int i=0; i<4; ++i)
sd.push(node2(sx,sy,i));
crack(0);
val[sx][sy]=4;
for(int t=1; t<=T; ++t) {
while(!sd.empty()) {
now=sd.front();
sd.pop();
next.x=now.x+dir[now.d][0];
next.y=now.y+dir[now.d][1];
next.d=now.d;
val[now.x][now.y]--;
if(!judge(next))continue;
val[next.x][next.y]++;
if(iswd(next))continue;
temp.push_back(next);
}
crack(t);
}
}
int main() {
int x,y,s;
while(scanf("%d%d%d%d",&r,&c,&n,&T)!=EOF) {
init();
for(int i=1; i<=n; ++i) {
scanf("%d%d%d",&x,&y,&s);
mpt[x][y]=1;
val[x][y]=s;
wd[i]=node1(x,y);
}
scanf("%d%d",&x,&y);
bfs(x,y);
for(int i=1; i<=n; ++i) {
if(ans[i]==-1) {
printf("1 %d\n",val[wd[i].x][wd[i].y]);
} else {
printf("0 %d\n",ans[i]);
}
}
}
return 0;
}