A. String Generation
签到
- 题设:T个样例下,每次给一对N和K(1≤k≤n≤1000),分别代表答案字符串的长度,和答案字符串中最长的回文子序列长度。规定:答案字符串只能用‘a’,‘b’,‘c’三种字符。输出任意符合要求的字符串。
- 思路:k大于等于1,让整个答案字符串最长的回文子序列长度为1即可,那么直接N长度下,循环输出‘a’,‘b’,‘c’即可。
B. Find the Spruce
动态规划
- 题设:T个样例下,每次输入n,m(1≤n,m≤500),和一张n×m的图,求这张图中可构成多少次云杉树。这里的云杉树可通俗化为:由数行构成,首行为一个星号,接下来每行星号长度增加2的轴对称“金字塔形”。
- 思路:最大500×500的图,正序暴力遍历不可取。
先对图进行处理,简化变成二维数组,有星号的位置标记为1。
再考虑逆向思维,倒序从下往上遍历,对是否构成最小的二层金字塔进行动态规划状态转移,并将当前位置累加进最后答案中。
状态转移方程:
dp【i】【j】= min(dp【i+1】【j】,min(dp【i+1】【j-1】,dp【i+1】【j+1】))+1;
——AC代码:
#include<bits/stdc++.h>
#define ll long long
#define SC(a) scanf("%d",&a)
#define mem(a,n) memset(a,n,sizeof(a))
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
priority_queue <int,vector<int>,less<int> > QM;
const int INF= 0x3f3f3f3f;
const int maxn= 2e5+5;
int n,m,dp[505][505];
int main()
{
IOS;
int t;
cin>>t;
while(t--)
{
cin>>n>>m;
mem(dp,0);
char c;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>c;
if(c=='*') dp[i][j]=1;
}
ll ans=0;
for(int i=n;i>=1;i--)
{
for(int j=1;j<=m;j++)
{
if(dp[i][j])
{
dp[i][j] = min(dp[i+1][j],min(dp[i+1][j-1],dp[i+1][j+1]))+1;
ans += dp[i][j];
}
}
}
cout<<ans<<endl;
}
return 0;
}
C. Random Events
思维 数学
- 题设:T个样例下,每次给定一对n,m(1≤n,m≤105),和长度为n的数组a【i】。然后是m个概率事件,每个事件有两个值,r和p,分别代表,此事件将会对数组a中下标【1,r】的元素进行自动升序排列,和这个事件发生的概率p。求:所有事件下,数组变成完全升序的概率。
- 思路:根据样例推断和题意理解易知:
1.若存在这样一个事件,只执行这它后数组就完全升序,将它标记。即只要这个特殊事件发生,其他事件任意组合,是否发生都不会影响结果。
2.找出符合条件的所有特殊事件,若它们都不发生,那么数组必然不会完全升序。那么答案就是:1-这些特殊事件同时不发生的概率(相互独立,累乘)
3.注意特判,若所有事件都是特殊事件,答案为1。若特殊事件总数为0,答案为0。
——AC代码:
#include<bits/stdc++.h>
#define ll long long
#define SC(a) scanf("%d",&a)
#define mem(a,n) memset(a,n,sizeof(a))
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
priority_queue <int,vector<int>,less<int> > QM;
const int INF= 0x3f3f3f3f;
const int maxn= 2e5+5;
int n,m,a[maxn];
bool vis[maxn];
struct node
{
int r;
double p;
}op[maxn];
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i],vis[i]=0;
for(int i=1;i<=m;i++) cin>>op[i].r>>op[i].p;
int cnt=0;
for(int i=n;i>=1;i--)
{
vis[i]=1, cnt++;
if(a[i]!=i) break;
}
if(cnt==n)
cout<<"1.000000"<<endl;//特判
else
{
int flag=0;
double ans=1;
for(int i=m;i>=1;i--)
{
int num=op[i].r;
if(vis[num]==1)
{
flag=1;
ans*=(1-op[i].p);
}
}
if(flag)
printf("%.6lf\n",1-ans);
else
cout<<"0.000000"<<endl;//特判
}
}
int main()
{
//IOS;
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}