T1
[模拟]
找循环节直接模拟即可。
【code】

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define File "rps"
inline void file(){
freopen(File".in","r",stdin);
freopen(File".out","w",stdout);
}
inline int read(){
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}
return x*f;
}
const int MAXN = 200 + 10;
int n, na, nb, a[MAXN], b[MAXN], cnta, cntb;
int vs[5][5] = {{0,0,1,1,0},{1,0,0,1,0},{0,1,0,0,1},{0,0,1,0,1},{1,1,0,0,0}}; //得分表的处理
int main(){
file();
n = read(),na = read(),nb = read();
for(int i = 0;i < na; ++i) a[i] = read();
for(int i = 0;i < nb; ++i) b[i] = read();
for(int i = 0; i < n; i++){
cnta += vs[a[i % na]][b[i % nb]]; //周期循环
cntb += vs[b[i % nb]][a[i % na]];
}
printf("%d %d\n",cnta,cntb);
return 0;
}
T2
[搜索?]
题意实际上就是要找到(a,b,c)满足a对b连边,b对c连边,求出树上所有这样的三元组的组数的联合权值,以及最大的联合权值。
我们只需枚举中间点是哪一个。
然后遍历它的所有出边,统计答案即可。
还要记得开longlong
求和可能会炸int
【code】

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define File "link"
inline void file(){
freopen(File".in","r",stdin);
freopen(File".out","w",stdout);
}
inline int read(){
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}
return x*f;
}
const int mxn = 2e5 + 10;
const int mod = 10007;
int n;
int w[mxn];
struct edge{
int nxt,y;
}e[mxn<<1];
int to[mxn],len;
inline void add(int xx,int yy){
e[++len].nxt = to[xx];
to[xx] = len;
e[len].y = yy;
}
int main(){
file();
n = read();
for(int i = 1;i < n; ++i){
int x = read(),y = read();
add(x,y),add(y,x);
}
for(int i = 1;i <= n; ++i) w[i] = read();
ll mx1(0),s1(0);
ll mx2(0),s2(0);
for(int x = 1;x <= n; ++x){
s2 = mx2 = 0;
for(int i = to[x]; i;i = e[i].nxt){
int y = e[i].y;
s1 = (s1 + 1ll*s2*w[y]) % mod;
mx1 = max(mx1,1ll*mx2*w[y]);
s2 = (s2 + (ll)w[y]) % mod;
mx2 = max(mx2,(ll)w[y]);
}
}
printf("%lld %lld\n",mx1,s1*2%mod);
return 0;
}
/*
5
1 2
2 3
3 4
4 5
1 5 2 3 10
*/
T3
[dp]
本题主要考虑的是如何满足水管在的情况。
F[i][j]表示横坐标为i,竖直距离为j的最少点击次数。
F[i][j] = min(f[i-1][j-x[i]],f[i][j-x[i]])+1;
F[i][j] = min(f[i][j],f[i-1][j+y[i]]);
如何保证不超过上下边界通过水管?
Dp值更新完之后,在边界以外的dp值赋为正无穷就好了。
由于能够转移而来的初值有限。所以f[0][i] = 0外其余均为正无穷。
【code】

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf f[0][0]
#define File "bird"
inline void file(){
freopen(File".in","r",stdin);
freopen(File".out","w",stdout);
}
inline int read(){
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}
return x*f;
}
const int mxn = 1e4 + 5;
const int mxm = 2e3 + 5;
int n,m,k;
int x[mxn],y[mxn];
bool v[mxn];
int l[mxn],h[mxn];
//每个位置可以飞到的上下界。
int f[mxn][mxm];
//横坐标为i高度为j的最少点击次数。
inline int min_(int x,int y){
return x > y ? y : x;
}
int main(){
file();
n = read(),m = read(),k = read();
for(int i = 1;i <= n; ++i)
x[i] = read(),y[i] = read(),l[i] = 1,h[i] = m;
memset(v,0,sizeof v);
for(int i = 1;i <= k; ++i){
int p = read(),a = read(),b = read();
l[p] = a+1, h[p] = b-1;
v[p] = 1;
}
memset(f,0x3f,sizeof f);
for(int i = 1;i <= m; ++i) f[0][i] = 0; //初值
for(int i = 1;i <= n; ++i){
for(int j = x[i]+1;j <= x[i]+m; ++j)
f[i][j] = min_(f[i-1][j-x[i]],f[i][j-x[i]])+1;
for(int j = m+1;j <= x[i]+m; ++j)
f[i][m] = min_(f[i][m],f[i][j]);
for(int j = 1;j <= m-y[i]; ++j)
f[i][j] = min_(f[i][j],f[i-1][j+y[i]]);
for(int j = 1;j < l[i]; ++j) f[i][j] = inf;
for(int j = h[i]+1;j <= m; ++j) f[i][j] = inf;
}
int ans = inf;
for(int i = 1;i <= m; ++i) ans = min_(ans,f[n][i]);
if(ans < inf){
puts("1");
printf("%d\n",ans);
return 0;
}
puts("0");
bool f_ = 1;
int i,j;
for(i = n;i >= 1; --i){
for(j = 1;j <= m; ++j){
if(f[i][j] < inf) {
break;
}
}
if(j <= m) break;
}
ans = 0;
for(int j = 1;j <= i; ++j)
if(v[j]) ans++;
printf("%d\n",ans);
return 0;
}
/*
10 10 4
1 2
3 1
2 2
1 8
1 8
3 2
2 1
2 1
2 2
1 2
1 0 2
6 7 9
9 1 4
3 8 10
*/
