这个月复习半期,好像有两周没上信息课
昨天终于开始了(想念OI的味道)
然鹅今天考试qwq
第一次考第一诶~ (虽然是在菜鸡班)
主要是因为巨佬都把文件名写错了:D
T1 Niven
模拟菜题
略
sol
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define re register
int niven,n;
inline int in{
int i=0,f=1;char ch;
while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
if(ch=='-')ch=getchar(),f=-1;
while(ch>='0'&&ch<='9')i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
inline int Load(int n){
int a=1,sum=0,tmp=n;
while(tmp){
sum+=a*(tmp%10);
a*=niven;
tmp/=10;
}
return sum;
}
inline int Sum(int n){
int sum=0,tmp=n;
while(tmp){
sum+=tmp%10;
tmp/=10;
}
return sum;
}
int main(){
// freopen("niven.in","r",stdin);
// freopen("niven.out","w",stdout);
niven=10;
while(niven){
niven=in;
if(!niven)return 0;
n=in;
if(Load(n)%Sum(n)==0)printf("yes\n");
else printf("no\n");
}
return 0;
}
T2 Sub
很庆幸zgs的数据太小、电脑太快
我O(N3)的暴力模拟都过了
sol
//O(n^3)可能T
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define re register
#pragma GCC optimize(2)
int n,len,m;
char ch[(int)2e3+10];
int ansl,ansh;
inline int in{
int i=0,f=1;char ch;
while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
if(ch=='-')ch=getchar(),f=-1;
while(ch>='0'&&ch<='9')i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
int main(){
// freopen("sub.in","r",stdin);
// freopen("sub.out","w",stdout);
n=in;
gets(ch);
len=strlen(ch);
for(re int i=0;i<len-n;i++)
for(re int j=i+n;j<len;j++){
if((j-i)%2==0)continue;
int l=i,r=((i+j)>>1)+1,h=((j-i)>>1)+1;
for(re int k=0;k<h;k++)
if(ch[l+k]!=ch[r+k])m++;
if(m<=n&&h>ansh)ansl=l,ansh=h;
m=0;
}
if(!ansh){
printf("Not found\n");
return 0;
}
printf("%d ",ansh*2);
for(re int i=0;i<ansh*2;i++)
printf("%c",ch[ansl+i]);
return 0;
}
改进的算法
用前缀和的思想
忽略字符,因为我们只需要比较字符不一样
为了不一直比较,直接枚举长度然后确定二者是否相同
那一次比较就是查询一段区间的和
我实在是看不懂zgs的丑陋至极的代码(if和while之间他竟然不换行T_T)
大概理解了一下:
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define re register
int n,len;
char ch[2010];
bool diff[2010];
int total[2010];
inline int in{
int i=0,f=1;char ch;
while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
if(ch=='-')ch=getchar(),f=-1;
while(ch>='0'&&ch<='9')i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
int main(){
n=in;
gets(ch);
len=strlen(ch);
bool found=false;
for(re int i=(len>>1);i>=1;i--){
for(re int j=i;j<=len;j++)
diff[j]=(ch[j]!=ch[j-i])?true:false;
total[i]=diff[i];
for(re int j=i+1;j<(i<<1);j++)
total[j]=total[j-1]+diff[j];
for(re int j=(i<<1);j<len;j++)
total[j]=total[j-1]+diff[j]-diff[j-i];
for(re int j=(i<<1)-1;j<len;j++)
if(total[j]<=n){
found=true;
char ans[2010];
int tot=0;
for(re int k=j-(i<<1)+1;k<=j;k++)
ans[tot++]=ch[k];
ans[(i<<1)]=0;
printf("%d %s\n",(i<<1),ans);
break;
}
if(found)break;
}
if(!found)puts("Not found");
return 0;
}
T3 News
读题有点日隆
他说的是从一个点开始,遍历(带边权)所用时间最短的
竟然没有想到用Floyd算法
数据小,O(N3)就搞定了(
N
∈
[
1
,
100
]
N \in [1,100]
N∈[1,100])
联通块判断:如果!Map[i][j]则disjoint
Floyd有点坑——先枚举i,j,k中哪一个是有考究的
研究一下
sol
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define re register
#define INF 0x7fffffff
int n;
int Map[110][110];
inline int in{
int i=0,f=1;char ch;
while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
if(ch=='-')ch=getchar(),f=-1;
while(ch>='0'&&ch<='9')i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
inline void Floyd(){
for(re int k=1;k<=n;k++)
for(re int i=1;i<=n;i++)
if(Map[i][k]&&i!=k)
for(re int j=1;j<=n;j++)
if(Map[k][j]&&i!=j&&j!=k)
if(!Map[i][j]||(Map[i][j]>Map[i][k]+Map[k][j]))
Map[i][j]=Map[i][k]+Map[k][j];
}
int main(){
n=in;
for(re int i=1;i<=n;i++){
int x=in;
for(re int j=1;j<=x;j++)
Map[i][in]=in;
}
Floyd();
int mint=INF,time=0,mini=0;
for(re int i=1;i<=n;i++){
time=0;
for(re int j=1;j<=n;j++)
if(i!=j){
if(time<Map[i][j])time=Map[i][j];
else if(Map[i][j]==0){
time=INF;
break;
}
}
if(time<mint){
mini=i;
mint=time;
}
}
if(mint==INF)printf("disjoint\n");
else printf("%d %d\n",mini,mint);
return 0;
}
T4 Arrange
先说这个结论:
感性认知(一会儿来证),矩阵中的每一排在排序后的数组中是连续的
很明显的二分:二分ans
构造的出来就往下缩
不行就往上走
O
(
N
l
o
g
2
N
)
O(Nlog_2N)
O(Nlog2N)
sol
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define re register
int n,r,c;
int p[(int)5e5+10];
int ans;
inline int in{
int i=0,f=1;char ch;
while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
if(ch=='-')ch=getchar(),f=-1;
while(ch>='0'&&ch<='9')i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
inline int check(int x){
int cnt=0;
for(re int i=1;i<=n-c+1;){
if(p[i+c-1]-p[i]<=x)cnt++,i+=c;
else i++;
}
return cnt;
}
int main(){
n=in,r=in,c=in;
for(re int i=1;i<=n;i++)p[i]=in;
sort(p+1,p+n+1);
int l=0,h=(int)1e9+1;
while(l<=h){
int mid=(l+h)>>1;
if(check(mid)>=r)h=mid-1,ans=mid;
else l=mid+1;
}
printf("%d\n",ans);
return 0;
}
写二分的时候把r和h搞混了T_T
关于结论 “矩阵中的每一排在排序后的数组中是连续的” 的证明:
反证法,假设有一行不连续
对于一行
R
i
R_i
Ri
假设
P
j
∈
[
R
i
,
m
i
n
,
R
i
,
m
a
x
]
P_j \in [R_{i,min},R_{i,max}]
Pj∈[Ri,min,Ri,max] 且
P
j
∉
R
i
P_j \notin R_i
Pj∈/Ri
s
w
a
p
(
P
j
,
R
i
,
m
a
x
)
swap(P_j,R_{i,max})
swap(Pj,Ri,max)
⇒
F
\Rightarrow F
⇒F不变
min(R[i])<=p[j]<=max(R[i])
swap(p[j],max(R[i])),不改变F
if(p[j]属于R[k]){
if(A:min(R[k])<=min(R[i]))
swap(p[j],min(R[i]))不增大F
else if(B:max(R[k])>=max(R[i]))
swap(p[j],max(R[i]))不增大F
else if(!A:min(R[k])>=min(R[i])&&!B:max(R[k])<=max(R[i])) 即均不满足上面两种情况
swap(max(R[k]),max(R[i]))不增大F
}
因此可以通过这些操作把每一行换成连续的
伪证毕