目录
一.第一题:孤独的数列 (lonely)
二.第二题:五颜六色 (color)
三.第三题:获取字符串 (obtain)
首先自我反思,因为打错了freopen导致爆零,这是重大的失误,以后绝对不能再犯。
一.第一题:孤独的数列 (lonely)
题目描述:
某一天,你走在路上的时候,看到地上有一个 n 个非负整数组成的序列(a1,a2,…,an)。
你很惊讶地发现:你总是能找到一个正整数 k,使得这个数列的任意 k 个连续正整数的按位或的结果都相同!也就是说,对于所有的(i,j)((1≤i,j≤n−k+1)),都有:
[ai∣ai+1∣…∣ai+k−1=aj∣aj+1∣…∣aj+k−1]
那么,我们定义能找到的最小的 k 就是这个序列的“孤独程度”。你的任务是找到给定的 T 个序列的每个序列的孤独程度。
题目思路:
暴力枚举k的所有可能,一旦这k为按位或运算的结果一直相同,就直接输出。
错因:
忘了按位或运算是什么了(上课不够认真,该罚!)
正确代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+1;
int t,n,a[N],x[N];
int read(){//快读
int ans=0,j=1;char c=getchar();
while(c>'9' or c<'0'){
if(c=='-')j=-1;
c=getchar();
}
while(c>='0' and c<='9'){
ans=ans*10+c-'0';
c=getchar();
}
return ans*j;
}
inline int ask(){
for(int i=1;i<n;i++){
memset(x,0,sizeof x);每一次计算后清零
bool flag=true;
for(int j=1;j<=n-i+1;j++){
for(int k=1;k<=i;k++) x[j]|=a[j+k-1];//计算每k个数的按位或运算的结果
if(x[j]!=x[j-1] && j!=1){//一旦有一个不同,k就不符合要求
flag=false;
break;
}
}
if(flag==true) return i;//如果符合就返回符合的值
}
return n;
}
signed main(){
freopen("lonely.in","r",stdin);
freopen("lonely.out","w",stdout);
t=read();
for(int i=1;i<=t;i++){
n=read();
memset(a,0,sizeof a);
for(int j=1;j<=n;j++) a[j]=read();//输入元素数组
printf("%d\n",ask());
}
return 0;
}
二.第二题:五颜六色 (color)
题目描述:
树是一种具有 n 个点和 n−1 条边的无向连通图。
六一儿童节快到了,老师安排你去给一棵树进行装饰,从而让其变得更好看。老师给了你 k 桶染料,每一种染料的颜色都不同。你需要将这棵树染色之后尽量显得不单调,具体来说:
- 对于树上任意两个距离不超过 2 的节点 x 和 y,其所染的颜色不相同。
你想要知道:一共有多少种染色方法,可以使得这棵树满足上述条件?不一定每一种颜料都需要使用。由于答案可能会很大,请输出答案对 109+7 取模后的结果。
题目思路:
在以1为根的距离为二之内的点进行赋值,再以赋值后的点重复之前的操作。
错因:
当时没想到这个思路(后来听到同学分享思路之后才知道的)。
正确代码:
#include<bits/stdc++.h>
using namespace std;
long long n,k,ans=1;
const int N=5e5+5;
const int mod=1e9+7;
int dis[N];
vector<int>v[N],w[N];
inline long long read() {//快读
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
void dfs(int x,int fa){//求每一个点的染色可能数
dis[x]=k;
for(int i=0;i<w[x].size();i++) if(dis[w[x][i]]) dis[x]--;
for(int i=0;i<v[x].size();i++){
if(v[x][i]==fa) continue;
dfs(v[x][i],x);
}
}
signed main(){
freopen("color.in","r",stdin);
freopen("color.out","w",stdout);
n=read(),k=read();
for(int i=1;i<n;i++){
int x,y;
x=read(),y=read();
v[x].push_back(y),v[y].push_back(x);
}
for(int i=1;i<=n;i++){//重新建边
for(int j=0;j<v[i].size();j++){
w[i].push_back(v[i][j]);
for(int l=0;l<v[v[i][j]].size();l++){
int z=v[v[i][j]][l];
if(i==z) continue;
w[i].push_back(z);
}
}
}
dfs(1,0);
for(int i=1;i<=n;i++) ans=ans*dis[i]%mod;
printf("%d",ans);
return 0;
}
三.第三题:获取字符串 (obtain)
题目描述:
Sofia 有一个初始长度为 n 的字符串 S,只包含小写英文字母。她可以对这个字符串进行以下类型的操作:
- 选择一个下标 i (1≤i≤∣S∣),并删除 Si。∣S∣ 表示字符串的长度。
- 选择两个整数 l,r,要求 (1≤l≤r≤∣S∣),然后对 Sl,Sl+1,…,Sr 按照从小到大进行排序。例如,对字符串
sofia
选择 l=2,r=4 的话,变化之后的字符串为sfioa
。
Sofia 想知道:对字符串 S 进行若干次上述两种操作之后,是否有可能得到另一个长度为 m 的字符串 T?
样例:
题目思路:
首先看修改之前的字符串与修改之后的字符串的长度是否相同。如有,将修改后的字符串在修改前的里没有的删除,在进行排序,否则直接进行排序。
错因:
排序实现错误(炸了)。
正确代码:
#include<bits/stdc++.h>
using namespace std;
int t,n,m;
string s,ch;
bool check(){
queue<int> q[207];
for(int i=0;i<n;i++) q[s[i]].push(i);//入队每个字符对应的下标
for(int i=0;i<m;i++){
if(q[ch[i]].size()==0) return false;//如果在修改前的字符串中没有修改后中的字符,输出NO
else{
for(char j='a';j<ch[i];j++){
while(q[j].size()&&q[j].front()<q[ch[i]].front()) q[j].pop();//在有这个字符的前提下并且修改后比他在字典序中靠前的的下标靠前的情况下进行出队
}
q[ch[i]].pop();
}
}
return true;
}
signed main(){
freopen("obtain.in","r",stdin);
freopen("obtain.out","w",stdout);
cin>>t;
while(t--){
cin>>n>>m;
cin>>s>>ch;
if(check()) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}