1001 GCD is Funny
思路:
此题真迷;
先两两gcd得出的结果re, f[re]=1;
然后re与除了得出re的父母的其他数gcd
代码:
#include <bits/stdc++.h>
using namespace std;
//不互质返回true
const int N=500+5;
const int M=1000+5;
int a[N];
int f[M];
int gcd(int x, int y){
return y?gcd(y,x%y):x;
}
int main(){
int t, n;
scanf("%d", &t);
while(t-->0){
memset(f,0,sizeof(f));
scanf("%d", &n);
for(int i=0; i<n; i++)
scanf("%d", &a[i]);
sort(a,a+n);
for(int i=0; i<n-1; i++)
for(int j=i+1; j<n; j++){
f[gcd(a[i],a[j])]=1;
}
int flag=1, len=n-1;
while(flag && len>=3){
len--;
flag = 0;
for(int i=1; i<=1000; i++)
if(f[i]){
for(int j=0; j<n; j++){
int t = gcd(i,a[j]);
if(!f[t]){
f[t] = 1;
flag=1;
}
}
}
}
flag=0;
for(int i=1; i<=a[n-1]; i++)
if(f[i]){
if(flag)
printf(" ");
flag=1;
printf("%d", i);
}
printf("\n");
}
return 0;
}
1002 Square Distance
思路:
比赛做了很久,怎么就没想出用dp做的呢,只怪自己太vegetable……
整个代码分为两步,让我们先用dp()判断是否可能,不可能就输出"Impossible" (without the quotes),否则按字典序最小的原则改动原数组
f[i][j] 代表从 i 到 (n/2-1) 的 j 代价能否实现,实现赋值1,for: n/2-1 to 0;
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 1000+5;
char arr[N];
int f[N/2][N];//从坐标i往后j代价能否实现,实现为1
int n, m;
int dp(){
memset(f,0,sizeof(f));
//注意边界条件
f[n/2][0] = 1;
for(int i=n/2-1; i>=0; i--){
if(arr[i]==arr[i+n/2]){
for(int j=0; j<=m; j++)
f[i][j] = f[i+1][j];//不改
for(int j=0; j<=m-2; j++)
if(f[i+1][j])
f[i][j+2] = 1;//改两个
continue;
}
for(int j=0; j<=m-1; j++)
if(f[i+1][j])
f[i][j+1] = 1;//改一个
for(int j=0; j<=m-2; j++)
if(f[i+1][j])
f[i][j+2] = 1;//改两个
}
if(f[0][m]) return 0;
return 1;
}
void change(){
int len=m, tmp;
for(int i=0; i<n/2; i++)
for(int j=0; j<26; j++){
tmp = 0;
if(arr[i] != j+'a') tmp++;
if(arr[i+n/2] != j+'a') tmp++;
if(f[i+1][len-tmp]){
arr[i] = arr[i+n/2] = j+'a';
len -= tmp;
break;
}
}
}
int main(){
int t;
scanf("%d", &t);
while(t-->0){
scanf("%d%d", &n, &m);
getchar();
gets(arr);
//判断是否存在
if(dp()){
printf("Impossible\n");
continue;
}
//以字典序最小原则改动原数组
change();
puts(arr);
}
return 0;
}
1003 LCIS
思路:
一开始被题目迷惑了,LCIS是最长公共子序列,于是我的小伙伴就一直在写LCIS的dp然后TLE然后尝试优化_(:зゝ∠)_
其实这道题是求LIS,两个字符串分别求LIS最长(连续)上升子序列就可以!对,只是需要注意是连续(x,x+1……y-1,y)的就好;
int f[N];//代表以a[i]为结尾的最长【连续】递增序列长度
状态转移方程 f[a[i]] = max{f[a[i]-1]+1, f[a[i]]};
求出来之后for循环找最大值即可
代码:
#include <bits/stdc++.h>
using namespace std;
/*
以a[i]为结尾的最长【连续】递增序列
f[a[i]] = max{f[a[i]-1]+1, f[a[i]]};
*/
#define my_max(x,y) (x>y?x:y)
#define my_min(x,y) (x<y?x:y)
const int N = 1e5+5;
const int M = 1e6+5;
int a[N];
int b[N];
int fa[M];
int fb[M];
int n, m;
void read(){
//memset(fa,0,sizeof(fa));
//memset(fb,0,sizeof(fb));
scanf("%d%d", &n, &m);
for(int i=0; i<n; i++){
scanf("%d", &a[i]);
fa[a[i]] = my_max(fa[a[i]], fa[a[i]-1]+1);
}
for(int i=0; i<m; i++){
scanf("%d", &b[i]);
fb[b[i]] = my_max(fb[b[i]], fb[b[i]-1]+1);
}
}
int main(){
int t;
scanf("%d", &t);
while(t-->0){
read();
int maxn=0;
for(int i=0; i<n; i++)
maxn = my_max(maxn, my_min(fa[a[i]],fb[a[i]]));//有个小陷阱坑了我!!!
printf("%d\n", maxn);
//注意fa(fb)里面是a[i](b[i])!!!
for(int i=0; i<n; i++) fa[a[i]] = 0;
for(int i=0; i<m; i++) fb[b[i]] = 0;
}
return 0;
}
注意:
此题用memset超时,因为他会把数组按长度全部赋值,太慢,如果想用memset,请在代码最最前面加上
#pragma comment(linker, "/STACK:1024000000,1024000000")
反思:
一开始想成f[i]是以 i 为结尾的最长连续递增序列长度,当然就TLE了,做了很多无用功;
附上错误代码,引以为鉴;
#include <bits/stdc++.h>
using namespace std;
/*
以i为结尾的最长【连续】递增序列
f[i] = max{f[i-1]+1, f[i]};
*/
const int N = 1e5;
int a[N];
int b[N];
int fa[N];
int fb[N];
int n, m;
void read(){
scanf("%d%d", &n, &m);
for(int i=0; i<n; i++)
scanf("%d", &a[i]);
for(int i=0; i<m; i++)
scanf("%d", &b[i]);
}
void dp(){
for(int i=0; i<n; i++){
fa[i] = 1;
for(int j=0; j<i; j++)
if(a[i]==a[j]+1 && fa[j]+1>fa[i])
fa[i] = fa[j]+1;
}
for(int i=0; i<m; i++){
fb[i] = 1;
for(int j=0; j<i; j++)
if(b[i]==b[j]+1 && fb[j]+1>fb[i])
fb[i] = fb[j]+1;
}
}
int main(){
int t;
scanf("%d", &t);
while(t-->0){
read();
dp();
int maxn=0;
for(int i=0; i<n; i++)
for(int j=0; j<m; j++){
if(fb[j]==fa[i] && b[j]==a[i])
maxn = maxn>fb[j]?maxn:fb[j];
}
printf("%d\n", maxn);
}
return 0;
}