1001 Blank
d
p
[
i
]
[
j
]
[
k
]
[
t
]
dp[i][j][k][t]
dp[i][j][k][t]表示
0
,
1
,
2
,
3
0,1,2,3
0,1,2,3出现的位置排序后为
i
,
j
,
k
,
t
i,j,k,t
i,j,k,t的方案数
枚举第
t
+
1
t+1
t+1位的情况进行转移
对于限制情况,固定右端点,暴力枚举所有状态,把所有非法状态清零
#include<iostream>
#include<vector>
#include<cstring>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define mp make_pair
using namespace std;
int n,m,res,i,l,r,x,t,tt,j,k,p;
int f[105][105][105][2];
vector<pair<int,int>> d[105];
int main()
{
int mod = 998244353;
int T;
scanf("%d",&T);
while (T--)
{
fo(i,1,n) d[i].clear();
scanf("%d%d",&n,&m);
fo(i,1,m)
{
scanf("%d%d%d",&l,&r,&x);
d[r].push_back(mp(l,x));
}
memset(f,0,sizeof(f));
f[0][0][0][0] = 1;
fo(t,1,n)
{
tt = t & 1;
fo(i,0,t) fo(j,i,t) fo(k,j,t) f[i][j][k][tt] = 0;
fo(i,0,t) fo(j,i,t) fo(k,j,t)
{
f[j][k][t-1][tt] = (f[j][k][t-1][tt] + f[i][j][k][tt^1]) % mod;
f[i][k][t-1][tt] = (f[i][k][t-1][tt] + f[i][j][k][tt^1]) % mod;
f[i][j][t-1][tt] = (f[i][j][t-1][tt] + f[i][j][k][tt^1]) % mod;
f[i][j][k][tt] = (f[i][j][k][tt] + f[i][j][k][tt^1]) % mod;
}
fo(i,0,t) fo(j,i,t) fo(k,j,t)
for (p = 0;p < d[t].size(); p++)
{
l = d[t][p].first; x = d[t][p].second;
if ((i>=l)+(j>=l)+(k>=l)+(t>=l) != x) f[i][j][k][tt] = 0;
}
}
res = 0;
fo(i,0,n) fo(j,i,n) fo(k,j,n)
res = (res + f[i][j][k][n&1]) % mod;
cout<<res<<endl;
}
return 0;
}
1004 Vacation
从近到远不断求出每辆车的速度函数
显然每辆车的速度是一个阶梯形(每次撞上前一辆车速度都会变小)
如何根据第
i
i
i辆车的图像得到
i
+
1
i+1
i+1辆车的图像?
先画出一条水平线表示初始速度,然后求什么时候两条曲线之间的面积等于两车初始距离(即什么时候追上),之后的速度图像一致
当然这个面积也可以是负数(表示前车开始过快,距离拉大)
时间复杂度为
O
(
n
)
O(n)
O(n)
记录图像的“阶梯拐点”(速度变化点)即可
#include<iostream>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
#define N 5000000
using namespace std;
int n,i,base,head,flag;
int l[N],s[N],v[N],p[N];
double t[N];
double d,dd;
int main()
{
while (~scanf("%d",&n))
{
n++;
fd(i,n,1) scanf("%d",&l[i]);
fd(i,n,1) scanf("%d",&s[i]);
fd(i,n,1) scanf("%d",&v[i]);
base = 100005;
t[base] = 0; p[base] = v[1];
t[base+1] = 1e14; p[base+1] = 0;
head = base;
fo(i,2,n)
{
d = s[i] - (s[i-1] + l[i-1]);
flag = 0;
while (d >= (t[head+1]-t[head]) * (v[i] - p[head]))//注意这里的等号
{
if (head == base) {flag = 1; break;}
d -= (t[head+1] - t[head]) * (v[i] - p[head]);
head++;
}
if (flag == 1)
{
t[base] = 0; p[base] = v[i];
continue;
}
dd = d / (v[i] - p[head]);
t[head] += dd;
head--;
t[head] = 0; p[head] = v[i];
}
d = s[n];
while (d > (t[head+1]-t[head]) * p[head])
{
d -= (t[head+1] - t[head]) * p[head];
head++;
}
dd = d / p[head];
t[head] += dd;
printf("%.10lf\n",t[head]);
}
return 0;
}
1005 Path
先保留所有最短路的边,即满足 d u − d v = w d_u-d_v=w du−dv=w的边,然后跑最小割
1009 String
暴力枚举每一位的字母,合法的依据是后缀能否满足条件
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
#define N 500000
using namespace std;
int n,i,j,T,head,nextpos,flag,suffix;
char ch[N];
queue<int> pos[30];
int a[N],l[30],r[30],cnt[N][30];
queue<int> res;
int resflag;
int main()
{
while (~scanf("%s",ch+1))
{
n = strlen(ch+1);
fo(i,1,n) a[i] = ch[i] - 'a' + 1;
scanf("%d",&T);
fo(i,1,26) scanf("%d%d",&l[i],&r[i]);
fo(i,1,n) fo(j,1,26) cnt[i][j] = cnt[i-1][j] + (a[i] == j);
fo(i,1,26) while (!pos[i].empty()) pos[i].pop();
while (!res.empty()) res.pop();
fo(i,1,n) pos[a[i]].push(i);
head = 0;
while (T--)
{
resflag = 0;
fo(i,1,26)
{
if (r[i] == 0) continue;
while (!pos[i].empty() && pos[i].front() <= head) pos[i].pop();
if (pos[i].empty()) continue;
nextpos = pos[i].front();
flag = 0; suffix = 0;
fo(j,1,26)
{
suffix += l[j];
if (l[j] && j == i) suffix--;
if (cnt[n][j] - cnt[nextpos-1][j] < l[j]) {flag = 1; break;}
if (T < suffix) {flag = 1; break;}
}
if (flag) continue;
if (l[i]) l[i]--; r[i]--;
res.push(i);
head = nextpos;
resflag = 1;
break;
}
if (resflag == 0) {cout<<-1; break;}
}
if (resflag == 1)
while (!res.empty()) {cout<<(char)('a'+res.front()-1); res.pop();}
cout<<endl;
}
return 0;
}
1013 Code
问题转化为能否用一条直线分开两类点
这个问题等价于两个凸包是否相交
两两比较两个凸包上的边是否相交即可
注意先判断所有点的凸包,特判内含的情况
#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;
const double eps=1e-10;
const int maxn=300;
struct point {
double x,y;
int id;
}pnt[maxn],pnt1[maxn],pnt2[maxn],res1[maxn],res2[maxn];
bool mult(point sp,point ep,point op) {
return (sp.x-op.x)*(ep.y-op.y)>=(ep.x-op.x)*(sp.y-op.y);
}
bool operator <(const point &l,const point &r) {
return l.y<r.y||(l.y==r.y&&l.x<r.x);
}
int graham(point pnt[],int n,point res[]) {
int len,k=0,top=1;
memset(res,0,sizeof res);
sort(pnt,pnt+n);
if(n==0) return 0;res[0]=pnt[0];
if(n==1) return 1;res[1]=pnt[1];
if(n==2) return 2;res[2]=pnt[2];
for(int i=2; i<n; i++) {
while(top&&mult(pnt[i],res[top],res[top-1])) top--;
res[++top]=pnt[i];
}
len=top;res[++top]=pnt[n-2];
for(int i=n-3; i>=0; i--) {
while(top!=len&&mult(pnt[i],res[top],res[top-1])) top--;
res[++top]=pnt[i];
}
return top;
}
bool inter(point a,point b,point c,point d)
{
if(min(a.x,b.x)>max(c.x,d.x)||
min(a.y,b.y)>max(c.y,d.y)||
min(c.x,d.x)>max(a.x,b.x)||
min(c.y,d.y)>max(a.y,b.y)) return 0;
double h,i,j,k;
h=(b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
i=(b.x-a.x)*(d.y-a.y)-(b.y-a.y)*(d.x-a.x);
j=(d.x-c.x)*(a.y-c.y)-(d.y-c.y)*(a.x-c.x);
k=(d.x-c.x)*(b.y-c.y)-(d.y-c.y)*(b.x-c.x);
return h*i<=eps&&j*k<=eps;
}
int main() {
int t,n,id;
int x,y;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
memset(pnt,0,sizeof pnt);
int n1=0,n2=0;
for(int i=0;i<n;i++){
scanf("%d%d%d",&x,&y,&id);
if (id == -1) id = 0;
pnt[i].x=x;pnt[i].y=y;pnt[i].id=id;
if(id==0){
pnt1[n1].x=x;pnt1[n1].y=y;pnt1[n1++].id=id;
}
else{
pnt2[n2].x=x;pnt2[n2].y=y;pnt2[n2++].id=id;
}
}
if(n==1||n==2){
cout<<"Successful!"<<endl;continue;
}
if(n1==n||n2==n){cout<<"Successful!"<<endl;continue;}
int m=graham(pnt,n,res1);
int cnt=0;
for(int i=0;i<m;i++) if(res1[i].id==1) cnt++;
if(cnt==0||cnt==m){cout<<"Infinite loop!"<<endl;continue;}
int m1=graham(pnt1,n1,res1);
int m2=graham(pnt2,n2,res2);
int flag=0;
for(int i=0;i<=m1-1;i++){
point a=res1[i],b;
if(i==m1-1) b=res1[0];
else b=res1[i+1];
for(int j=0;j<=m2-1;j++){
point c=res2[j],d;
if(j==m2-1) d=res2[0];
else d=res2[j+1];
if(inter(a,b,c,d)){flag=1;break;}
}
if(flag) break;
}
if(flag) cout<<"Infinite loop!"<<endl;
else cout<<"Successful!"<<endl;
}
return 0;
}