G题 Link with Monotonic Subsequence
题目:输出长度为n的最长上升序列和最长下降序列的最大值最小的排列。把n分成近似于sqrt(n)的组,组外上升,组内下降即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline void solve(){
int n;
scanf("%d",&n);
double len=ceil(sqrt(n));
//cout<<len<<endl;
for(int i=n%int(len);i>=1;i--){
cout<<n-i+1<<" ";
}
for(int i=n/len;i>=1;i--){
for(int j=1;j<=len;j++){
int x=(i-1)*len;
cout<<x+j<<" ";
}
}
cout<<endl;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int t;
scanf("%d",&t);
while(t--){
solve();
}
return 0;
}
K题 Link with Bracket Sequence I
思路:f[i][j][k]表示在补全序列的前i位中,包含原序列的前j位,左括号-右括号=k(下标从0开始,天然保证了左括号数量大于等于右括号数量,也就是保证了构造出来的序列肯定是满足成为一个合法括号序列的,后面就不需要再考虑是否合法了),的方案数
答案就是f[m][n][0]。如果j=0,也就是一个都不匹配;可以在第i位放左括号,则+=f[i-1][j][k-1],因此,需要k>=1才行;可以在第i位放右括号,则+=f[i-1][j][k+1]。否则,如果s[j]=‘(’,也就是说前j位都匹配了,且第j位为左括号;可以是补全序列的第i位匹配s[j],则+=f[i-1][j - 1][k - 1],需要k大于等于1;也可是是补全序列的第[1,i-1]中的某一位匹配上了s[j],则+=f[i-1][j][k + 1]。否则,前j位都匹配了,且第j位为右括号;可以是补全序列的第i位匹配s[j],则+=f[i-1][j - 1][k + 1];也可是是补全序列的第[1,i-1]中的某一位匹配上了s[j],则+=f[i-1][j][k - 1],需要k大于等于1。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 210;
const int mod = 1e9+7;
int n,m,f[N][N][N];
char s[N];
void add(int &x,int y){
x=(x+y)%mod;
}
inline void solve(){
scanf("%d%d%s",&n,&m,s+1);
for(int i=0;i<=m;i++){
for(int j=0;j<=n;j++){
for(int k=0;k<=m;k++){
f[i][j][k]=0;
}
}
}
f[0][0][0]=1;
for(int i=0;i<m;i++){
for(int j=0;j<=n;j++){
for(int k=0;k<=i;k++){
add(f[i+1][j+(s[j+1]=='(')][k+1],f[i][j][k]);
if(k) add(f[i+1][j+(s[j+1]==')')][k-1],f[i][j][k]);
}
}
}
printf("%d\n",f[m][n][0]);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int t;
scanf("%d",&t);
while(t--){
solve();
}
return 0;
}
J题 Link with Arithmetic Progression
思路:最小二乘法拟合公式。
#include <bits/stdc++.h>
#include <cstdio>
#include <cctype>
#include <vector>
namespace GTI{
char gc(void)
{
const int S = 1 << 16;
static char buf[S], *s = buf, *t = buf;
if (s == t) t = buf + fread(s = buf, 1, S, stdin);
if (s == t) return EOF;
return *s++;
}
int gti(void)
{
int a = 0, b = 1, c = gc();
for (; !isdigit(c); c = gc()) b ^= (c == '-');
for (; isdigit(c); c = gc()) a = a * 10 + c - '0';
return b ? a : -a;
}
}
using GTI::gti;
// using namespace GTI;
using namespace std;
typedef long long ll;
using Parameter = struct {
double k; // 斜率
double b; // 截距
};
// 最小二乘法计算过程
bool LeastSquares(std::vector<double>& X, std::vector<double>& Y, Parameter& param)
{
if (X.empty() || Y.empty())
return false;
int vec_size = X.size();
double sum1 = 0, sum2 = 0;
double x_avg = std::accumulate(X.begin(), X.end(), 0.0) / vec_size;
double y_avg = std::accumulate(Y.begin(), Y.end(), 0.0) / vec_size;
for (int i = 0; i < vec_size; ++i) {
sum1 += (X.at(i) * Y.at(i) - x_avg * y_avg);
sum2 += (X.at(i) * X.at(i) - x_avg * x_avg);
}
param.k = sum1 / sum2;
param.b = y_avg - param.k * x_avg;
return true;
}
double a[100005];
// 主函数
int main(int argc, char* argv[])
{
int t;
// cin>>t;
t=gti();
while(t--){
ll n;
// cin>>n;
n=gti();
Parameter param{ 0, 0 };
vector<double> x_vec,y_vec;
for(int i=1;i<=n;i++){
// cin>>a[i];
a[i]=gti();
x_vec.push_back(i);
y_vec.push_back(a[i]);
}
LeastSquares(x_vec, y_vec, param);
// printf("y=%lfx+%lf\n",param.k,param.b);
double yi,ans=0;
for(int i=1;i<=n;i++){
yi=param.k*i+param.b;
ans+=(yi-a[i])*(yi-a[i]);
}
printf("%.15lf\n",ans);
}
}