- codeforces訓練
- C. Hungry Games
本題大意就是找到最後g不等於0的區間個數。
主要思路:找字首和第一次大於k的下標idx(二分),然後我們發現idx+1的方案數相當於把idx+1當作左端點來算,然後我們就想到dp[i]代表以i為左端點的方案數。
總結:在比賽的時候找到了idx,但是因為沒有想到用dp來表示,所以是一直遞迴下去,然後因為一些邊界問題還是沒有寫出來。
ps:本題因為需要用到後面的狀態,所以我們從後往前二分來做。
一般這種區間的問題,就是以左端點或者右端點為起點,然後在較小的時間複雜度內找到符合條件的區間數。
#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
int dx[4]={0,0,-1,1};
int dy[4]={-1,1,0,0};
#define int long long
typedef pair<int,int> pii;
const int N=200010;
int s[N];
int a[N];
int n,k;
int dp[N];
void solve()
{
cin>>n>>k;
memset(s,0,sizeof s);
memset(dp,0,sizeof dp);
for(int i=1;i<=n;i++)
{
cin>>a[i];
s[i]=s[i-1]+a[i];
}
int ans=0;
for(int i=n;i>=1;i--)
{
int l=i-1,r=n+1;
while(l+1<r)
{
int mid=l+r>>1;
if(s[mid]-s[i-1]>k)
{
r=mid;
}else l=mid;
}
if(r==n+1)dp[i]+=n-i+1;
else dp[i]=dp[r+1]+r-i;
}
for(int i=1;i<=n;i++)ans+=dp[i];
cout<<ans<<endl;
}
signed main()
{
int good_luck_to_you;
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
// good_luck_to_you=1;
cin>>good_luck_to_you;
while(good_luck_to_you--)
{
solve();
}
system("pause");
}
- C. Arrow Path
DFS
// LUOGU_RID: 171384671
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MOD = 1e9 + 7;
const int MAX_N = 3e5 + 5;
int n;
bool vis[3][200005];
char mp[3][200005];
vector<int> g[MAX_N];
bool st[MAX_N];
int qpow(int a, int b, int m) {
int result = 1;
a %= m;
while (b > 0) {
if (b & 1) {
result = (result * a) % m;
}
a = (a * a) % m;
b >>= 1;
}
return result;
}
int xx[]={0,0,1,-1};
int yy[]={1,-1,0,0};
bool inmp(int x,int y){
return x>0&&x<3&&y>0&&y<n+1;
}
void dfs(int tx,int ty){
vis[tx][ty]=true;
if(tx==2 and ty==n){
return;
}
for(int i=0;i<4;i++){
int x=tx+xx[i];
int y=ty+yy[i];
if(inmp(x,y)&&!vis[x][y]){
vis[x][y]=true;
if(mp[x][y]=='>'&&y+1<=n&&!vis[x][y+1]){
dfs(x,y+1);
}
vis[x][y]=false;
if(mp[x][y]=='<'&&y-1>=1&&!vis[x][y-1]){
dfs(x,y-1);
}
vis[x][y]=false;
}
}
}
int32_t main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
cin>>t;
while(t--){
cin>>n;
for(int i=1;i<=2;i++){
for(int j=1;j<=n;j++){
cin>>mp[i][j];
}
}
memset(vis,false,sizeof(vis));
dfs(1,1);
if(vis[2][n])cout<<"YES"<<'\n';
else cout<<"NO"<<'\n';
}
return 0;
}
3.C. Naming Company
-
nowcoder訓練
1.挖溝
最小生成數的板子題
克魯斯卡爾演算法和普利姆演算法
最小生成樹模板題。
prim演算法:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2*500000+10;
const int maxnn = 100000+10;
struct sy{
int to;
int next;
int w;
} edge[maxn];
int head[maxn];
struct Node{
int number;
int w;
bool operator < (const Node &n) const {
return w>n.w;
}
};
priority_queue<Node> pq;
bool vis[maxnn];
int cnt = 0;
int n, m;
void add_edge(int x, int y, int w)
{
edge[++cnt].next = head[x];
edge[cnt].to = y;
edge[cnt].w = w;
head[x] = cnt;
}
//普利姆演算法,利用貪心的原理求最小生成樹
int prim()
{
int ans = 0;
pq.push({1, 0});
while (pq.size())
{
Node node = pq.top();
pq.pop();
int number = node.number;
int w = node.w;
if (vis[number]) continue;
ans += w;
vis[number] = true;
//遍歷這個點的其他邊,找出沒有遍歷過的加入
for (int i=head[number];i;i = edge[i].next)
{
int next = edge[i].to;
// cout<<next<<" "<<edge[i].w<<endl;
if (vis[next]) continue;
pq.push({next, edge[i].w});
}
}
return ans;
}
int main()
{
int x, y ,w;
cin>>n>>m;
for (int i=1;i<=m;i++)
{
cin>>x>>y>>w;
add_edge(x, y, w);
add_edge(y, x, w);
}
int ans = prim();
cout<<ans;
return 0;
}
克魯斯卡爾演算法:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2*500000+10;
struct Node{
int x, y, w;
} node[maxn];
bool comp(Node n1, Node n2)
{
return n1.w<n2.w;
}
int fa[100000+10];
int n, m;
int find(int x)
{
return fa[x]==0?x:fa[x] = find(fa[x]);
}
int main()
{
cin>>n>>m;
for (int i=1;i<=m;i++)
{
cin>>node[i].x>>node[i].y>>node[i].w;
}
sort(node+1, node+1+m, comp);
int ans = 0;
for (int i=1;i<=m;i++)
{
int x = node[i].x;
int y = node[i].y;
int rootx = find(x);
int rooty = find(y);
if (rootx==rooty) continue;
ans += node[i].w;
fa[rootx] = rooty;
}
cout<<ans<<endl;
return 0;
}
2.道路建設
還是最小生成樹的板子
#include<bits/stdc++.h>
using namespace std;
const int maxn=10005,maxm=100005;
struct E{
int from,next,to,dis;
}edge[maxm*2];
int c,n,m,u,v,w;
int head[maxn],cnt=0,fa[maxn];
int find(int x){
if(fa[x]==x) return x;
else return fa[x]=find(fa[x]);
}
void unite(int x,int y){
fa[find(x)]=find(y);
}
void addedge(int from,int to,int dis){
edge[++cnt].next=head[from];
edge[cnt].from=from;
edge[cnt].to=to;
edge[cnt].dis=dis;
head[from]=cnt;
}
bool cmp(E a,E b){
return a.dis<b.dis;
}
int main(){
scanf("%d%d%d",&c,&n,&m);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
addedge(v,u,w);
}
int tot=0,sm=0;
for(int i=1;i<=m;i++) fa[i]=i;
sort(edge+1,edge+1+cnt,cmp);
for(int i=1;i<=cnt;i++){
if(find(edge[i].to)!=find(edge[i].from)){
sm+=edge[i].dis;
unite(edge[i].to,edge[i].from);
tot++;
}
if(tot==m-1) break;
}
if(sm<=c) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
return 0;
}