C题 Constructive Problems Never Die
思路:把数字分为在A中出现过和没出现过两种,在构造的时候先用出现过的数字填补,这里我选择的是用错位填补的方法,即Pi=A(i+1),如果遇到相同的数字,就用没出现过的数字填补即可。
#include <bits/stdc++.h>
using namespace std;
const int maxn=100010;
typedef long long ll;
int read(){
int m=0,n=1;
char ch;
ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
n=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
m=m*10+ch-'0';
ch=getchar();
}
return m*n;
}
int main(){
int t,n,f;
t=read();
while(t--){//1e5
vector<int> v;
n=read();
vector<int> a(n+5),vis(n+1),num(n+1);
f=0;
for(int i=1;i<=n;i++){
num[i]=0;
a[i]=read();
if(i!=1&&a[i]!=a[i-1]) f=1;
vis[a[i]]++;
}
if(f==0){
puts("NO");
}else{
for(int i=1;i<=n;i++){
if(vis[i]==0){//如果这个元素在a数组没出现过,说明在p中可以放在任意位置
v.push_back(i);
}
}
int x=0;
puts("YES");
a[n+1]=a[1];
for(int i=1;i<=n;i++){
if(num[a[i+1]]==0&&a[i+1]!=a[i]){
printf("%d ",a[i+1]);
num[a[i+1]]++;
}else{
printf("%d ",v[x]);
x++;
}
}
printf("\n");
}
}
return 0;
}
F题 Candies
思路:n个人围成一个圈,每个人有一个数字,相邻的人数字相同或者是数字相加为一个给定的数字x就可以消除,然后组成新的圈,问能消除的最大次数。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int vis[N],ne[N];
ll n,x;
ll v[N];
int qu(int a,int b){
int ans=0;
if(a==b) return 0;
if(v[b]==v[a]||v[b]+v[a]==x){
//修改相邻位置的值
vis[ne[a]]=vis[b];
ne[vis[b]]=ne[a];
//表示已经被访问过了,记录位置
vis[b]=b;
vis[a]=a;
ans+=qu(ne[a],vis[ne[a]])+1;
}
return ans;
}
int main(){
scanf("%lld%lld",&n,&x);
for(int i=0;i<n;i++) scanf("%lld",&v[i]);
ll ans=0;
for(int i=0;i<n;i++){
vis[i]=(i+1)%n;//记录i的下一个相邻位置
ne[i]=(i-1+n)%n;//记录i的上一个相邻位置
}
for(int i=0;i<n;i++){
if(vis[i]==i) {//如果vis[i]==i,说明已经被消除了
continue;
}
ans+=qu(i,vis[i]);
}
printf("%lld",ans);
}
G题 Regular Expression
思路:如果字符串长度为一,答案只能是“.”或者它本身两种;如果长度为2,在两个字母相同的情况下,有8种,不同则有6种;如果长度大于2,则都可以用两个符号表示,比如“.+”。模没啥用。
#include<bits/stdc++.h>
using namespace std;
int t;
string s;
int main(){
cin>>t;
while(t--){
cin>>s;
int f=0;
for(int i=0;i<s.size()-1;i++){
if(s[i]!=s[i+1]) {
f=1;break;
}
}
if(s.size()==1) cout<<1<<" "<<2<<endl;
else if(f==0&&s.size()==2) cout<<2<<" "<<8<<endl;
else if(f==1&&s.size()==2) cout<<2<<" "<<6<<endl;
else if(f==1) cout<<2<<" "<<2<<endl;
else cout<<2<<" "<<4<<endl;
}
}
J题 Melborp Elcissalc
思路:能整除k的数字被认为是好的数字。一个数组只包含小于k的非负数,它的优度定义为和能整除k的非空连续子数组的个数。求长度为n优度为t的数组的个数,对答案取模。
#include<cstdio>
using namespace std;
const int M=998244353;
int n,K,t;
long f[65][2100];//第一维记录长度,第二维记录优度
long C[70][70];//
int main(){
scanf("%d%d%d",&n,&K,&t);
C[0][0]=1;
for(int i=1;i<=65;i++){
C[i][0]=1;
for(int j=1;j<=i;j++)
C[i][j]=(C[i-1][j-1]+C[i-1][j])%M;
}
f[0][0]=1;
for(int u,i=0;i<K;i++)
for(int k=n;k;k--)
for(int l=t;l>=0;l--){
for(int u,j=1;j<=k;j++){
u=j*(i==0?(j+1):(j-1))/2;
if(u>l) break;
//第一维记录长度,第二维记录优度
f[k][l]+=f[k-j][l-u]*C[k][j]%M;
}
f[k][l]%=M;
}
printf("%ld\n",f[n][t]);
}