@wwwqeqeqeqe
2019-04-26T20:55:04.000000Z
字数 5281
阅读 745
codeforces
题目大意:
给你n个数据和Serval到达车站的时间。接下来n行,每行输出公交车第一班到车站的时间以及之后每隔t分钟就会再来一班,问Serval会上哪一种车?如果有多种答案,任意输出其中一种。
解题思路:
暴力算出每种车在Serval到达车站后的第一班车到车站的时间,再任意输出其中时间最早的那一班车的号数。
代码:
#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=1e5+5;
int n,t,x,y,ans[maxn];
int main()
{
cin >> n >> t;
for(int i=0;i<n;i++)
{
cin >> x >> y;
if(x >= t)
ans[i]=x;
else
{
int p=t-x;
if(p%y)
{
p/=y;
p++;
p*=y;
p+=x;
}
else
{
p=t;
}
ans[i]=p;
}
}
int cnt=INF,mark=0;
for(int i=0;i<n;i++)
{
if(ans[i]<cnt)
{
cnt=ans[i];
mark=i+1;
}
}
cout << mark << endl;
}
题目大意:
给出一个图形的长宽高,并给出前视图、左视图看到的这个图形每个位置的高度,再给出俯视图看到的每个方格内是否有物品,输出这个图形本来的模样。如有多个结果,任意输出其中一个
解题思路:
因为题目给出了这个图形的正视图和左视图,我们就能具体到第几行第几列最多有多少个格子,再通过俯视图给出的信息,删去其中不满足条件的,就能够得到我们需要的图形之一。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e2+5;
int n,m,h;
int x;
int mp[maxn][maxn];
int main()
{
cin >> n >> m >> h;
memset(mp,0x3f,sizeof(mp));
for(int i=0;i<m;i++)
{
cin >> x;
for(int j=0;j<n;j++)
{
mp[j][i]=min(mp[j][i],x);
}
}
for(int i=0;i<n;i++)
{
cin >> x;
for(int j=0;j<m;j++)
{
mp[i][j]=min(mp[i][j],x);
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
cin >> x;
if(x == 0)
{
mp[i][j]=0;
}
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m-1;j++)
{
cout << mp[i][j] << " ";
}
cout << mp[i][m-1] << endl;
}
return 0;
}
题目大意:
给出字符串的总长度n以及n个带'(',')','?'的字符串,问是否能通过改变其中的'?',带得到前1,前2,前3......前n-1个左右括号都不满足括号匹配但整个字符串满足。
解题思路:
因为他要保证前面的括号都不满足括号匹配单最后结果满足,我们可以利用贪心的方法,将最左边的几个?变为(,使整个字符串的(数量等于n/2,再将剩下的?变为),最后判断变完后的字符串是否满足题目要求。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+5;
int n,l,r;
char s[maxn];
int main()
{
cin >> n;
cin >> s;
if(n%2)
{
cout << ":(" << endl;
}
else
{
l=r=n/2;
for(int i=0; i<n; i++)
{
if(s[i] == '(')
{
l--;
}
else if(s[i] == ')')
r--;
}
if(l<0 || r<0)
{
cout << ":(" << endl;
}
else
{
for(int i=0; i<n; i++)
{
if(s[i] == '?')
{
if(l)
{
l--;
s[i]='(';
}
else
{
r--;
s[i]=')';
}
}
}
l=0;
int mark=0;
for(int i=0; i<n; i++)
{
if(s[i] == '(')
l++;
else
l--;
if(i!=n-1 && l <= 0)
{
mark=1;
break;
}
}
if(mark == 0)
cout << s << endl;
else
cout << ":(" << endl;
}
}
return 0;
}
题目大意:
给出一棵树,并且这棵树存在k个叶子节点,然后对这k个叶子节点赋予1~k之间的数字,不能重复。在普通节点上,有0、1两个权值,1表示对当前节点所有的孩子节点求最大值,0取最小值。最后使1节点的值最大。
解题思路:
设d[x]=k表示节点x能够到达的x的子树中最大的叶子节点为第k大,如果x为叶子节点,那么显然d[x]=1,如果x节点的权值为1(及取最大值),那么x取他子节点中最大的那个,及d[x]=min(d[y])(y为x的子节点)。如果x节点的权值为0(及取最小值)那么没有办法,我们只能取所有x子节点的和才能使x取到的最小值最大,即d[x]=∑d[y]。
代码:
#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=3e5+5;
int n;
int mark[maxn],x,d[maxn];
vector<int> t[maxn];
int cnt=0;
void dfs(int p)
{
if(t[p].size() == 0)
{
d[p]=1;
cnt++;
return;
}
if(mark[p] == 1)
{
d[p]=INF;
for(int i=0;i<t[p].size();i++)
{
dfs(t[p][i]);
d[p]=min(d[p],d[t[p][i]]);
}
}
else
{
for(int i=0;i<t[p].size();i++)
{
dfs(t[p][i]);
d[p]+=d[t[p][i]];
}
}
}
int main()
{
cin >> n;
for(int i=1;i<=n;i++)
{
cin >> mark[i];
}
for(int i=2;i<=n;i++)
{
cin >> x;
t[x].push_back(i);
}
dfs(1);
cout << cnt+1-d[1] << endl;
return 0;
}
题目大意:
这个题是一道交互题。题目给你一个n*n的图,图中有一条蛇,你可以通过最多2019次查找,查询任意一个矩形,系统会告诉你蛇身穿过矩形边界的次数。你最后告诉系统,你找到的蛇的头尾分别在哪。
解题思路:
根据题目,我们可以知道,如果我们查询的结果为偶数,那么说明蛇的头尾都在矩形内或者都在矩形外。当查询结果为奇数时,则头尾一外一内。那么,我们先从列开始,设矩形的一个角为(1,1),另一个点为(n,i),当我们对i进行枚举,查询到刚好使结果为奇数时,说明这里有一个点的列坐标为当前的i,同理,我们反向进行搜索,得到另一个列坐标i2,即为另一个点的列坐标。找到两个点的列坐标后,我们通过二分查找在寻找两个点的行坐标(同样按照返回值的奇偶数值来判断)。最后确定两个点,即为我们的答案。如果一开始查找列坐标是,没有找到满足条件的列坐标,那么,我们可以确定,蛇的头尾列坐标是同一个,我们就另外通过行坐标来进行相同操作判断两个点的行坐标分别是多少,最后同样通过二分查找来寻找我们需要的列坐标。
代码:
#include<bits/stdc++.h>
using namespace std;
int n;
int ax1,ax2,ay1,ay2;
int x,i,j;
int main()
{
cin >> n;
for(i=1; i<n; i++)
{
printf("? 1 1 %d %d\n",n,i);
fflush(stdout);
scanf("%d",&x);
if(x&1)
break;
}
if(i != n)
{
for(j=n; j>1; j--)
{
printf("? 1 %d %d %d\n",j,n,n);
fflush(stdout);
scanf("%d",&x);
if(x&1)
break;
}
int l=1,r=n;
while(l<r)
{
int mid=(l+r+1) >> 1;
printf("? %d %d %d %d\n",mid,i,n,i);
fflush(stdout);
scanf("%d",&x);
if(x&1)
l=mid;
else
r=mid-1;
}
ax1=r,ay1=i;
l=1,r=n;
while(l<r)
{
int mid=(l+r+1) >> 1;
printf("? %d %d %d %d\n",mid,j,n,j);
fflush(stdout);
scanf("%d",&x);
if(x&1)
l=mid;
else
r=mid-1;
}
ax2=r,ay2=j;
}
else
{
for(i=1; i<n; i++)
{
printf("? 1 1 %d %d\n",i,n);
fflush(stdout);
scanf("%d",&x);
if(x&1)
break;
}
for(j=n; j>1; j--)
{
printf("? %d 1 %d %d\n",j,n,n);
fflush(stdout);
scanf("%d",&x);
if(x&1)
break;
}
int l=1,r=n;
while(l<r)
{
int mid=(l+r+1) >> 1;
printf("? %d %d %d %d\n",i,mid,i,n);
fflush(stdout);
scanf("%d",&x);
if(x&1)
l=mid;
else
r=mid-1;
}
ax1=i,ay1=r;
l=1,r=n;
while(l<r)
{
int mid=(l+r+1) >> 1;
printf("? %d %d %d %d\n",j,mid,j,n);
fflush(stdout);
scanf("%d",&x);
if(x&1)
l=mid;
else
r=mid-1;
}
ax2=j,ay2=r;
}
printf("! %d %d %d %d\n",ax1,ay1,ax2,ay2);
return 0;
}
题目大意:
在一条长度为L的数列上随机放n个线段,求被至少k条线段覆盖的区间的总长度期望。
解题思路:
首先可以发现,这n个线段的2*n个端点可以把线段分成2*n+1段,因为端点是随机的,所以每一段期望是相同的,都是l/(2*n+1)。所以,只需要计算每一段被至少k段区间覆盖的概率。我们假设区间长度为1,最后结果乘以l,设d[i][j][k]表示前i个点中有j个点还没有匹配成线段,k只有0或1,表示x点放了还是没放。那么,我们可以得到:
dp[i+1][j+1][k]+=dp[i][j][k](该点作为左端点)
dp[i+1][j-1][k]+=dp[i][j][k](该点作为右端点)
dp[i+1][j][1]+=dp[i][j][0](j>=k)(该点作为x,保证至少被k条线段覆盖)
最后,我们要将方案数除以总数才是期望。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 4e3 + 5;
const int mod = 998244353;
ll fac[maxn];
int dp[maxn][maxn][2];
void add(int &x,int y)
{
x = (x+y)%mod;
}
ll quick_pow(ll x,ll y)
{
ll ans = 1;
while(y)
{
if(y&1)
ans = ans*x%mod;
y >>= 1;
x = x*x%mod;
}
return ans;
}
int main()
{
int n,k,L;
cin >> n >> k >> L;
fac[0] = dp[0][0][0] = 1;
for(int i=1; i<maxn; i++)
fac[i] = fac[i-1]*i%mod;
int c = 2*n + 1;
for(int i=0; i<c; i++)
{
for(int j=0; j<=i; j++)
{
add(dp[i+1][j+1][0],dp[i][j][0]);
add(dp[i+1][j+1][1],dp[i][j][1]);
if(j)
{
add(dp[i+1][j-1][0],1ll*dp[i][j][0]*j%mod);
add(dp[i+1][j-1][1],1ll*dp[i][j][1]*j%mod);
}
if(j>=k) add(dp[i+1][j][1],dp[i][j][0]);
}
}
ll ans = fac[n]*quick_pow(2,n)%mod*dp[c][0][1]%mod*L%mod;
cout << ans*quick_pow(fac[c],mod-2)%mod << endl;
return 0;
}