A | B | C | D | E |
---|---|---|---|---|
√ | √ | √ | √ |
( √:做出; ●:尝试未做出; ○:已补题 )
题目地址:https://codeforces.com/contest/1388
这一次的题目好难读懂题……然后题目难度不大,就是做得太慢了。
题意:如果一个数 x 可以分解为 p ⋅ q p\cdot q p⋅q 并且 p 和 q 都为质数且不相等的形式,那么 x 就是一个近似质数。现在给出一个正整数 n,问 n 能否分解成四个不同的数的和,使得这四个数中至少有三个是近似质数。
思路:真是具有欺骗性。其实只要找出最小的 4 个近似质数(分别是 6,10,14,15),然后分解就行了。
代码:
#define DIN freopen("input.txt","r",stdin);
#define DOUT freopen("output.txt","w",stdout);
#include
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> P;
int read()
{
int x=0,flag=1; char c=getchar();
while((c>'9' || c<'0') && c!='-') c=getchar();
if(c=='-') flag=0,c=getchar();
while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return flag?x:-x;
}
int main()
{
int T=read();
while(T--)
{
int n=read();
if(n<=30) puts("NO");
else
{
puts("YES");
if(n-30==6 || n-30==10 || n-30==14) printf("6 10 15 %d\n",n-31);
else printf("6 10 14 %d\n",n-30);
}
}
return 0;
}
题意:水题。
思路:
代码:
#define DIN freopen("input.txt","r",stdin);
#define DOUT freopen("output.txt","w",stdout);
#include
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> P;
int read()
{
int x=0,flag=1; char c=getchar();
while((c>'9' || c<'0') && c!='-') c=getchar();
if(c=='-') flag=0,c=getchar();
while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return flag?x:-x;
}
int main()
{
int T=read();
while(T--)
{
int n=read();
int x=(n-1)/4+1;
REP(i,1,n-x) putchar('9');
REP(i,1,x) putchar('8');
puts("");
}
return 0;
}
题意:题意好复杂。大致意思就是有一棵树,1 号是根结点,每个结点都是一座城市,每个结点都有若干个人居住。一开始所有人都在 1 号结点,心情为 good 或者 bad。现在每个人都要由最短路回家,在路上心情可能会从 good 变成 bad(但不会反向变)。每个结点都记录了一个值 h,表示经过这个结点的 good 的人数减去 bad 的人数。现在给出所有数据,问每个结点的 h 是否合法。
思路:计算每个结点的 size,根据 size 和 h 可以唯一确定经过这个结点 good 和 bad 的人数(或者说明不合法),然后因为人不可能从 bad 变成 good,所以一个结点的 good 的人数一定不会小于它儿子的 good 的人数之和。就在树上 dfs 一下就可以全部算出来了。
在这里记录一下我总是犯的一个错误:误以为 G[x].size()<=1 代表的就是叶子,殊不知也有可能是根结点,这个错误已经犯了好多次了。
代码:
#define DIN freopen("input.txt","r",stdin);
#define DOUT freopen("output.txt","w",stdout);
#include
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> P;
int read()
{
int x=0,flag=1; char c=getchar();
while((c>'9' || c<'0') && c!='-') c=getchar();
if(c=='-') flag=0,c=getchar();
while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return flag?x:-x;
}
const int maxn=1e5+5;
VI G[maxn];
LL p[maxn],n,m,h[maxn],g[maxn],b[maxn],flag,siz[maxn];
void dfs(int u,int fa)
{
siz[u]=p[u];
for(int v:G[u]) if(v!=fa)
dfs(v,u),siz[u]+=siz[v];
LL x=(h[u]+siz[u])/2,y=x-h[u];
if(x<0 || y<0 || x+y!=siz[u] || x-y!=h[u]) flag=0;
g[u]=x; b[u]=y;
LL sum=0;
for(int v:G[u]) if(v!=fa) sum+=g[v];
if(sum>g[u]) flag=0;
//cout<
}
int main()
{
int T=read();
while(T--)
{
int n=read(),m=read(); flag=1;
REP(i,1,n) G[i].clear(),g[i]=b[i]=siz[i]=0;
REP(i,1,n) p[i]=read();
REP(i,1,n) h[i]=read();
REP(i,1,n-1)
{
int x=read(),y=read();
G[x].pb(y); G[y].pb(x);
}
dfs(1,0);
puts(flag?"YES":"NO");
}
return 0;
}
题意:有两个数组 a 和 b( − 1 0 6 ≤ a i ≤ 1 0 6 -10^6\le a_i \le 10^6 −106≤ai≤106, 1 ≤ b i ≤ n o r b i = − 1 1\le b_i\le n\ or \ b_i=-1 1≤bi≤n or bi=−1),现在要对每个位置 i 按照如下方法操作一次:将 a i a_i ai 累加到 ans,然后如果 b i ≠ − 1 b_i\neq -1 bi=−1,就令 a b i + = a i a_{b_i}+=a_i abi+=ai 。问最后 ans 的最大值,并且输出操作序列。
思路:其实也很简单,就是按照拓扑序进行操作。第一次拓扑序操作时,对于某个结点 i,如果 a i ≥ 0 a_i\ge 0 ai≥0,那么将其标记,累加答案并且将其加入 a b i a_{b_i} abi ,否则不对其进行标记;第二次拓扑序对所有没进行标记的进行处理,按照反拓扑序选择。其实思路就是贪心,如果正数就尽量累加到后面,如果负数就反向拓扑序,也就是不让它累加。
代码:
#define DIN freopen("input.txt","r",stdin);
#define DOUT freopen("output.txt","w",stdout);
#include
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> P;
int read()
{
int x=0,flag=1; char c=getchar();
while((c>'9' || c<'0') && c!='-') c=getchar();
if(c=='-') flag=0,c=getchar();
while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return flag?x:-x;
}
const int maxn=2e5+5;
VI an;
LL a[maxn],b[maxn],ans;
int n,vis[maxn],du[maxn],nxt[maxn];
int main()
{
n=read();
REP(i,1,n) a[i]=read();
REP(i,1,n) b[i]=read();
REP(i,1,n) if(b[i]!=-1) nxt[i]=b[i],du[b[i]]++;
queue<int> que;
REP(i,1,n) if(!du[i]) que.push(i);
while(!que.empty())
{
int i=que.front(); que.pop();
if(vis[i]) continue;
if(a[i]>=0)
{
vis[i]=1;
an.pb(i);
ans+=a[i];
if(nxt[i]>0) a[nxt[i]]+=a[i];
}
if(nxt[i]>0) du[nxt[i]]--;
if(nxt[i]>0 && du[nxt[i]]==0) que.push(nxt[i]);
}
stack<int> st;
REP(i,1,n) du[i]=0;
REP(i,1,n) if(!vis[i] && nxt[i]>0) du[nxt[i]]++;
REP(i,1,n) if(!vis[i] && !du[i]) que.push(i);
while(!que.empty())
{
int i=que.front(); que.pop();
vis[i]=1;
st.push(i);
ans+=a[i];
if(nxt[i]>0) du[nxt[i]]--;
if(nxt[i]>0 && !du[nxt[i]] && !vis[nxt[i]]) que.push(nxt[i]);
}
while(!st.empty()) an.pb(st.top()),st.pop();
printf("%lld\n",ans);
for(int i:an) printf("%d ",i);
return 0;
}
题意:
思路:
代码: